use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use meerkat_core::lifecycle::core_executor::{CoreApplyOutput, CoreExecutorError};
use meerkat_core::lifecycle::run_primitive::RunPrimitive;
use meerkat_core::lifecycle::{CoreExecutor, InputId, RunId};
use crate::meerkat_machine::dsl as mm_dsl;
#[cfg(not(target_arch = "wasm32"))]
pub(crate) use crate::tokio::time::Instant;
#[cfg(target_arch = "wasm32")]
pub(crate) use meerkat_core::time_compat::Instant;
pub(crate) const RUN_EXECUTION_START_NOTICE: Duration = Duration::from_secs(120);
pub(crate) const RUN_EXECUTION_START_BOUND: Duration = Duration::from_secs(3_600);
const _: () = assert!(
RUN_EXECUTION_START_NOTICE.as_secs() < RUN_EXECUTION_START_BOUND.as_secs(),
"the run-execution notice tier must fire strictly before the hard bound"
);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum TurnStartSignal {
Signalled,
NotSignalled,
}
#[derive(Clone, Default)]
pub(crate) struct TurnStartSignalCell(Arc<AtomicBool>);
impl TurnStartSignalCell {
pub(crate) fn mark_signalled(&self) {
self.0.store(true, Ordering::SeqCst);
}
fn signal(&self) -> TurnStartSignal {
if self.0.load(Ordering::SeqCst) {
TurnStartSignal::Signalled
} else {
TurnStartSignal::NotSignalled
}
}
}
#[derive(Clone)]
pub(crate) struct RunStartWindow {
pub(crate) run_id: RunId,
pub(crate) staged_at: Instant,
pub(crate) turn_start: TurnStartSignalCell,
}
#[derive(Clone, Default)]
pub(crate) struct SharedRunStartWindowCell {
inner: Arc<std::sync::Mutex<Option<RunStartWindow>>>,
}
impl SharedRunStartWindowCell {
pub(crate) fn arm(&self, run_id: RunId, staged_at: Instant, turn_start: TurnStartSignalCell) {
*self
.inner
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = Some(RunStartWindow {
run_id,
staged_at,
turn_start,
});
}
pub(crate) fn snapshot(&self) -> Option<RunStartWindow> {
self.inner
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.clone()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum RunStartHealth {
Clear,
Overdue,
Unreadable,
}
pub(crate) fn observe_run_start_window(
cell: &SharedRunStartWindowCell,
authority: &crate::driver::ephemeral::SharedIngressDslAuthority,
notice: Duration,
) -> RunStartHealth {
let Some(window) = cell.snapshot() else {
return RunStartHealth::Clear;
};
if window.staged_at.elapsed() < notice {
return RunStartHealth::Clear;
}
let Some((facts, signal)) =
read_run_turn_state_facts(authority, &window.run_id, &window.turn_start)
else {
return RunStartHealth::Unreadable;
};
if !facts.run_is_current {
return RunStartHealth::Clear;
}
if !facts.runtime_bound || signal == TurnStartSignal::NotSignalled {
return RunStartHealth::Unreadable;
}
if facts.applying_primitive {
RunStartHealth::Overdue
} else {
RunStartHealth::Clear
}
}
pub(crate) const QUEUED_INPUT_START_NOTICE: Duration = RUN_EXECUTION_START_NOTICE;
pub(crate) const PARKED_STAGE_CHURN_ATTEMPTS: u64 = 2;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ParkedQueuedWorkAxis {
AgedInQueue,
StageChurn,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ParkedQueuedWorkHealth {
Clear,
Parked(ParkedQueuedWorkAxis),
Unreadable,
}
pub(crate) fn observe_parked_queued_work(
authority: &crate::driver::ephemeral::SharedIngressDslAuthority,
driver: &crate::meerkat_machine::driver::SharedDriver,
notice: Duration,
now: chrono::DateTime<chrono::Utc>,
) -> ParkedQueuedWorkHealth {
let queued_inputs: Vec<(String, u64)> = {
let authority = match authority.try_lock() {
Ok(authority) => authority,
Err(std::sync::TryLockError::Poisoned(poisoned)) => poisoned.into_inner(),
Err(std::sync::TryLockError::WouldBlock) => {
return ParkedQueuedWorkHealth::Unreadable;
}
};
let state = authority.state();
if state.registration_phase != mm_dsl::RegistrationPhase::Active {
return ParkedQueuedWorkHealth::Clear;
}
if state.current_run_id.is_some() {
return ParkedQueuedWorkHealth::Clear;
}
state
.input_phases
.iter()
.filter(|(_, phase)| **phase == mm_dsl::InputPhase::Queued)
.map(|(key, _)| {
let attempts = state.input_attempt_counts.get(key).copied().unwrap_or(0);
(key.clone(), attempts)
})
.collect()
};
if queued_inputs.is_empty() {
return ParkedQueuedWorkHealth::Clear;
}
let driver = match driver.try_lock() {
Ok(driver) => driver,
Err(_) => return ParkedQueuedWorkHealth::Unreadable,
};
let ledger = driver.ledger();
let past = |since: chrono::DateTime<chrono::Utc>| {
now.signed_duration_since(since)
.to_std()
.is_ok_and(|elapsed| elapsed >= notice)
};
for (key, attempts) in &queued_inputs {
let Some(input_id) = uuid::Uuid::parse_str(key).ok().map(InputId::from_uuid) else {
continue;
};
let Some(state) = ledger.get(&input_id) else {
continue;
};
if past(state.updated_at()) {
return ParkedQueuedWorkHealth::Parked(ParkedQueuedWorkAxis::AgedInQueue);
}
if *attempts >= PARKED_STAGE_CHURN_ATTEMPTS && past(state.created_at) {
return ParkedQueuedWorkHealth::Parked(ParkedQueuedWorkAxis::StageChurn);
}
}
ParkedQueuedWorkHealth::Clear
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct RunTurnStateFacts {
pub(crate) runtime_bound: bool,
pub(crate) run_is_current: bool,
pub(crate) applying_primitive: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum RunExecutionProgress {
Executing,
PrimitiveUnapplied,
RunNotCurrent,
RuntimeUnbound,
ExecutionStartUnobservable,
Unreadable,
}
impl RunExecutionProgress {
pub(crate) fn proves_execution_never_started(self) -> bool {
matches!(self, Self::PrimitiveUnapplied)
}
pub(crate) fn closes_execution_start_window(self) -> bool {
matches!(self, Self::Executing | Self::RunNotCurrent)
}
pub(crate) fn execution_start_is_unobservable(self) -> bool {
matches!(
self,
Self::RuntimeUnbound | Self::ExecutionStartUnobservable
)
}
pub(crate) fn as_str(self) -> &'static str {
match self {
Self::Executing => "Executing",
Self::PrimitiveUnapplied => "PrimitiveUnapplied",
Self::RunNotCurrent => "RunNotCurrent",
Self::RuntimeUnbound => "RuntimeUnbound",
Self::ExecutionStartUnobservable => "ExecutionStartUnobservable",
Self::Unreadable => "Unreadable",
}
}
}
pub(crate) fn classify_execution_start(
facts: RunTurnStateFacts,
turn_start: TurnStartSignal,
) -> RunExecutionProgress {
if !facts.runtime_bound {
return RunExecutionProgress::RuntimeUnbound;
}
if turn_start == TurnStartSignal::NotSignalled {
return RunExecutionProgress::ExecutionStartUnobservable;
}
if !facts.run_is_current {
return RunExecutionProgress::RunNotCurrent;
}
if facts.applying_primitive {
RunExecutionProgress::PrimitiveUnapplied
} else {
RunExecutionProgress::Executing
}
}
pub(crate) trait RunExecutionProgressSource: Send + Sync {
fn observe(&self, run_id: &RunId) -> RunExecutionProgress;
}
pub(crate) struct AuthorityRunExecutionProgress {
authority: crate::driver::ephemeral::SharedIngressDslAuthority,
turn_start: TurnStartSignalCell,
}
impl AuthorityRunExecutionProgress {
pub(crate) fn new(
authority: crate::driver::ephemeral::SharedIngressDslAuthority,
turn_start: TurnStartSignalCell,
) -> Self {
Self {
authority,
turn_start,
}
}
}
impl RunExecutionProgressSource for AuthorityRunExecutionProgress {
fn observe(&self, run_id: &RunId) -> RunExecutionProgress {
match read_run_turn_state_facts(&self.authority, run_id, &self.turn_start) {
None => RunExecutionProgress::Unreadable,
Some((facts, signal)) => classify_execution_start(facts, signal),
}
}
}
fn read_run_turn_state_facts(
authority: &crate::driver::ephemeral::SharedIngressDslAuthority,
run_id: &RunId,
turn_start: &TurnStartSignalCell,
) -> Option<(RunTurnStateFacts, TurnStartSignal)> {
let authority = match authority.try_lock() {
Ok(authority) => authority,
Err(std::sync::TryLockError::Poisoned(poisoned)) => poisoned.into_inner(),
Err(std::sync::TryLockError::WouldBlock) => return None,
};
let state = authority.state();
let current = state
.current_run_id
.as_ref()
.and_then(crate::meerkat_machine::dsl_authority::current_run_id_from_dsl);
let facts = RunTurnStateFacts {
runtime_bound: state.active_runtime_id.is_some(),
run_is_current: current.as_ref() == Some(run_id),
applying_primitive: state.turn_phase == mm_dsl::TurnPhase::ApplyingPrimitive,
};
Some((facts, turn_start.signal()))
}
pub(crate) struct StagedRunStartWatchdog {
handle: crate::tokio::task::JoinHandle<()>,
}
impl StagedRunStartWatchdog {
pub(crate) fn spawn(
progress: Arc<dyn RunExecutionProgressSource + 'static>,
run_id: RunId,
input_ids: Vec<InputId>,
staged_at: Instant,
notice_every: Duration,
) -> Self {
let handle = crate::tokio::spawn(async move {
loop {
crate::tokio::time::sleep(notice_every).await;
let observed = progress.observe(&run_id);
if observed.closes_execution_start_window() {
return;
}
let staged_secs = staged_at.elapsed().as_secs();
let inputs = input_ids
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(",");
if observed.execution_start_is_unobservable() {
tracing::warn!(
%run_id,
%inputs,
observed = observed.as_str(),
staged_secs,
"staged run has not returned and its execution start is unobservable; \
the execution-start bound cannot arm for this run"
);
} else {
tracing::error!(
%run_id,
%inputs,
observed = observed.as_str(),
staged_secs,
bound_secs = RUN_EXECUTION_START_BOUND.as_secs(),
"staged run has not begun executing; its consumer accepted the run and \
applied nothing"
);
}
}
});
Self { handle }
}
}
impl Drop for StagedRunStartWatchdog {
fn drop(&mut self) {
self.handle.abort();
}
}
pub(crate) async fn apply_with_execution_start_bound(
executor: &mut dyn CoreExecutor,
progress: &dyn RunExecutionProgressSource,
run_id: RunId,
primitive: RunPrimitive,
staged_at: Instant,
bound: Duration,
) -> Result<CoreApplyOutput, CoreExecutorError> {
let apply_future = executor.apply(run_id.clone(), primitive);
let mut apply_future = std::pin::pin!(apply_future);
let deadline = crate::tokio::time::sleep(bound.saturating_sub(staged_at.elapsed()));
let mut deadline = std::pin::pin!(deadline);
crate::tokio::select! {
biased;
result = &mut apply_future => return result,
() = deadline.as_mut() => {}
}
let observed = progress.observe(&run_id);
let staged_secs = staged_at.elapsed().as_secs();
if !observed.proves_execution_never_started() {
if observed.execution_start_is_unobservable() {
tracing::warn!(
%run_id,
observed = observed.as_str(),
staged_secs,
bound_secs = bound.as_secs(),
"staged run passed its execution-start bound with its start unobservable; \
leaving the run in flight"
);
} else {
tracing::error!(
%run_id,
observed = observed.as_str(),
staged_secs,
bound_secs = bound.as_secs(),
"staged run passed its execution-start bound but non-progress is unproven; \
leaving the run in flight"
);
}
return apply_future.await;
}
tracing::error!(
%run_id,
observed = observed.as_str(),
staged_secs,
bound_secs = bound.as_secs(),
"runtime loop concluded its executor never began executing a staged run; terminalizing the run and handing the executor off"
);
Err(
CoreExecutorError::executor_not_progressing_requires_teardown(format!(
"runtime loop observed run {run_id} with its primitive still un-applied {staged_secs} seconds after staging; the executor never began executing it"
)),
)
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
mod tests {
use super::*;
use meerkat_core::lifecycle::core_executor::CoreExecutorTeardownReason;
use std::sync::atomic::{AtomicU8, AtomicUsize};
struct ScriptedProgress {
observations: std::sync::Mutex<Vec<RunExecutionProgress>>,
cursor: AtomicU8,
}
impl ScriptedProgress {
fn new(observations: Vec<RunExecutionProgress>) -> Arc<Self> {
Arc::new(Self {
observations: std::sync::Mutex::new(observations),
cursor: AtomicU8::new(0),
})
}
fn observation_count(&self) -> u8 {
self.cursor.load(Ordering::SeqCst)
}
}
impl RunExecutionProgressSource for ScriptedProgress {
fn observe(&self, _run_id: &RunId) -> RunExecutionProgress {
let index = usize::from(self.cursor.fetch_add(1, Ordering::SeqCst));
let observations = self
.observations
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
observations
.get(index)
.copied()
.or_else(|| observations.last().copied())
.unwrap_or(RunExecutionProgress::Unreadable)
}
}
struct ScriptedExecutor {
delay: Option<Duration>,
cancelled: Arc<AtomicBool>,
}
impl ScriptedExecutor {
fn wedged(cancelled: Arc<AtomicBool>) -> Self {
Self {
delay: None,
cancelled,
}
}
fn slow(delay: Duration, cancelled: Arc<AtomicBool>) -> Self {
Self {
delay: Some(delay),
cancelled,
}
}
}
struct CancelWitness {
cancelled: Arc<AtomicBool>,
completed: bool,
}
impl Drop for CancelWitness {
fn drop(&mut self) {
if !self.completed {
self.cancelled.store(true, Ordering::SeqCst);
}
}
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
impl CoreExecutor for ScriptedExecutor {
async fn apply(
&mut self,
_run_id: RunId,
_primitive: RunPrimitive,
) -> Result<CoreApplyOutput, CoreExecutorError> {
let mut witness = CancelWitness {
cancelled: Arc::clone(&self.cancelled),
completed: false,
};
match self.delay {
Some(delay) => {
crate::tokio::time::sleep(delay).await;
witness.completed = true;
Err(CoreExecutorError::Internal("scripted completion".into()))
}
None => {
std::future::pending::<()>().await;
unreachable!("wedged executor never returns")
}
}
}
async fn cancel_after_boundary(
&mut self,
_reason: String,
) -> Result<(), CoreExecutorError> {
Ok(())
}
async fn stop_runtime_executor(
&mut self,
_reason: String,
) -> Result<(), CoreExecutorError> {
Ok(())
}
}
fn run_id() -> RunId {
RunId::new()
}
fn staged_primitive() -> RunPrimitive {
RunPrimitive::StagedInput(meerkat_core::lifecycle::run_primitive::StagedRunInput {
boundary: meerkat_core::lifecycle::run_primitive::RunApplyBoundary::RunStart,
appends: Vec::new(),
contributing_input_ids: Vec::new(),
turn_metadata: None,
})
}
const TEST_BOUND: Duration = Duration::from_secs(900);
#[tokio::test(start_paused = true)]
async fn wedged_consumer_produces_a_typed_bounded_outcome() {
let cancelled = Arc::new(AtomicBool::new(false));
let mut executor = ScriptedExecutor::wedged(Arc::clone(&cancelled));
let progress = ScriptedProgress::new(vec![RunExecutionProgress::PrimitiveUnapplied]);
let run_id = run_id();
let error = crate::tokio::time::timeout(
TEST_BOUND * 4,
apply_with_execution_start_bound(
&mut executor,
progress.as_ref(),
run_id.clone(),
staged_primitive(),
Instant::now(),
TEST_BOUND,
),
)
.await
.expect("a consumer that never began executing must not hang mute")
.expect_err("a consumer that never began executing must produce a typed outcome");
assert!(
matches!(
error,
CoreExecutorError::TeardownRequired {
reason: CoreExecutorTeardownReason::ExecutorNotProgressing,
..
}
),
"expected a typed ExecutorNotProgressing teardown, got {error:?}"
);
assert!(
error.requires_runtime_teardown(),
"a wedged consumer must hand its executor off instead of receiving the next batch"
);
assert_eq!(
progress.observation_count(),
1,
"escalation must rest on exactly one observation, taken at the bound"
);
}
#[tokio::test(start_paused = true)]
async fn slow_but_executing_turn_is_not_disturbed_by_the_bound() {
let cancelled = Arc::new(AtomicBool::new(false));
let mut executor = ScriptedExecutor::slow(TEST_BOUND * 10, Arc::clone(&cancelled));
let progress = ScriptedProgress::new(vec![RunExecutionProgress::Executing]);
let result = apply_with_execution_start_bound(
&mut executor,
progress.as_ref(),
run_id(),
staged_primitive(),
Instant::now(),
TEST_BOUND,
)
.await;
assert!(
matches!(result, Err(CoreExecutorError::Internal(message)) if message == "scripted completion"),
"an executing turn must return its own outcome"
);
assert!(
!cancelled.load(Ordering::SeqCst),
"a live turn must never be cancelled by the execution-start bound"
);
}
#[tokio::test(start_paused = true)]
async fn the_bound_is_measured_from_staging_not_from_apply_entry() {
let cancelled = Arc::new(AtomicBool::new(false));
let mut executor = ScriptedExecutor::wedged(Arc::clone(&cancelled));
let progress = ScriptedProgress::new(vec![RunExecutionProgress::PrimitiveUnapplied]);
let staged_at = Instant::now();
crate::tokio::time::sleep(TEST_BOUND).await;
let elapsed_before = Instant::now();
let error = crate::tokio::time::timeout(
TEST_BOUND * 4,
apply_with_execution_start_bound(
&mut executor,
progress.as_ref(),
run_id(),
staged_primitive(),
staged_at,
TEST_BOUND,
),
)
.await
.expect("a run already past its window must not be granted a fresh one")
.expect_err("a run already past its window must produce a typed outcome");
assert!(
matches!(
error,
CoreExecutorError::TeardownRequired {
reason: CoreExecutorTeardownReason::ExecutorNotProgressing,
..
}
),
"expected a typed ExecutorNotProgressing teardown, got {error:?}"
);
assert!(
elapsed_before.elapsed() < TEST_BOUND,
"pre-apply time must count against the window, not extend it"
);
}
#[tokio::test(start_paused = true)]
async fn unprovable_observations_leave_even_a_wedged_run_in_flight() {
for observed in [
RunExecutionProgress::Unreadable,
RunExecutionProgress::RuntimeUnbound,
RunExecutionProgress::ExecutionStartUnobservable,
RunExecutionProgress::RunNotCurrent,
RunExecutionProgress::Executing,
] {
let cancelled = Arc::new(AtomicBool::new(false));
let mut executor = ScriptedExecutor::wedged(Arc::clone(&cancelled));
let progress = ScriptedProgress::new(vec![observed]);
let outcome = crate::tokio::time::timeout(
TEST_BOUND * 4,
apply_with_execution_start_bound(
&mut executor,
progress.as_ref(),
run_id(),
staged_primitive(),
Instant::now(),
TEST_BOUND,
),
)
.await;
assert!(
outcome.is_err(),
"{} must refuse to terminalize and keep awaiting its consumer",
observed.as_str()
);
}
}
#[tokio::test(start_paused = true)]
async fn unprovable_observations_do_not_disturb_a_slow_but_live_turn() {
for observed in [
RunExecutionProgress::Unreadable,
RunExecutionProgress::RuntimeUnbound,
RunExecutionProgress::ExecutionStartUnobservable,
RunExecutionProgress::RunNotCurrent,
] {
let cancelled = Arc::new(AtomicBool::new(false));
let mut executor = ScriptedExecutor::slow(TEST_BOUND * 10, Arc::clone(&cancelled));
let progress = ScriptedProgress::new(vec![observed]);
let result = apply_with_execution_start_bound(
&mut executor,
progress.as_ref(),
run_id(),
staged_primitive(),
Instant::now(),
TEST_BOUND,
)
.await;
assert!(
matches!(result, Err(CoreExecutorError::Internal(message)) if message == "scripted completion"),
"{} must leave the run in flight rather than terminalize it",
observed.as_str()
);
assert!(
!cancelled.load(Ordering::SeqCst),
"{} must not cancel an in-flight turn",
observed.as_str()
);
}
}
#[test]
fn an_unsignalled_turn_start_is_unobservable_not_executing() {
for applying_primitive in [true, false] {
let facts = RunTurnStateFacts {
runtime_bound: true,
run_is_current: true,
applying_primitive,
};
assert_eq!(
classify_execution_start(facts, TurnStartSignal::NotSignalled),
RunExecutionProgress::ExecutionStartUnobservable,
"an unsignalled turn start must never be read as a fact about this run"
);
}
}
#[test]
fn a_signalled_turn_start_classifies_the_shared_phase_as_this_run() {
let base = RunTurnStateFacts {
runtime_bound: true,
run_is_current: true,
applying_primitive: true,
};
assert_eq!(
classify_execution_start(base, TurnStartSignal::Signalled),
RunExecutionProgress::PrimitiveUnapplied
);
assert_eq!(
classify_execution_start(
RunTurnStateFacts {
applying_primitive: false,
..base
},
TurnStartSignal::Signalled
),
RunExecutionProgress::Executing
);
assert_eq!(
classify_execution_start(
RunTurnStateFacts {
run_is_current: false,
..base
},
TurnStartSignal::Signalled
),
RunExecutionProgress::RunNotCurrent
);
for turn_start in [TurnStartSignal::Signalled, TurnStartSignal::NotSignalled] {
assert_eq!(
classify_execution_start(
RunTurnStateFacts {
runtime_bound: false,
..base
},
turn_start
),
RunExecutionProgress::RuntimeUnbound,
"an unbound runtime is unobservable regardless of the turn-start signal"
);
}
}
#[test]
fn only_positive_facts_close_the_execution_start_window() {
for observed in [
RunExecutionProgress::Executing,
RunExecutionProgress::RunNotCurrent,
] {
assert!(
observed.closes_execution_start_window(),
"{} is a positive fact that closes the window",
observed.as_str()
);
}
for observed in [
RunExecutionProgress::PrimitiveUnapplied,
RunExecutionProgress::Unreadable,
RunExecutionProgress::RuntimeUnbound,
RunExecutionProgress::ExecutionStartUnobservable,
] {
assert!(
!observed.closes_execution_start_window(),
"{} leaves the staged -> executing window open",
observed.as_str()
);
}
}
#[test]
fn only_a_proven_unapplied_primitive_may_terminalize() {
assert!(RunExecutionProgress::PrimitiveUnapplied.proves_execution_never_started());
for observed in [
RunExecutionProgress::Executing,
RunExecutionProgress::RunNotCurrent,
RunExecutionProgress::RuntimeUnbound,
RunExecutionProgress::ExecutionStartUnobservable,
RunExecutionProgress::Unreadable,
] {
assert!(
!observed.proves_execution_never_started(),
"{} is not proof that execution never started",
observed.as_str()
);
}
}
struct CountingProgress {
observation: RunExecutionProgress,
observations: AtomicUsize,
}
impl RunExecutionProgressSource for CountingProgress {
fn observe(&self, _run_id: &RunId) -> RunExecutionProgress {
self.observations.fetch_add(1, Ordering::SeqCst);
self.observation
}
}
#[tokio::test(start_paused = true)]
async fn the_watchdog_keeps_reporting_an_open_window() {
for observation in [
RunExecutionProgress::PrimitiveUnapplied,
RunExecutionProgress::Unreadable,
RunExecutionProgress::ExecutionStartUnobservable,
RunExecutionProgress::RuntimeUnbound,
] {
let progress = Arc::new(CountingProgress {
observation,
observations: AtomicUsize::new(0),
});
let watchdog = StagedRunStartWatchdog::spawn(
Arc::clone(&progress) as Arc<dyn RunExecutionProgressSource>,
run_id(),
vec![InputId::new()],
Instant::now(),
Duration::from_secs(120),
);
crate::tokio::time::sleep(Duration::from_secs(500)).await;
drop(watchdog);
let reported = progress.observations.load(Ordering::SeqCst);
assert!(
reported >= 4,
"{} leaves the window open and must be re-reported every notice interval, got {reported}",
observation.as_str()
);
}
}
#[tokio::test(start_paused = true)]
async fn the_watchdog_stands_down_once_the_run_is_executing() {
let progress = Arc::new(CountingProgress {
observation: RunExecutionProgress::Executing,
observations: AtomicUsize::new(0),
});
let watchdog = StagedRunStartWatchdog::spawn(
Arc::clone(&progress) as Arc<dyn RunExecutionProgressSource>,
run_id(),
vec![InputId::new()],
Instant::now(),
Duration::from_secs(120),
);
crate::tokio::time::sleep(Duration::from_secs(500)).await;
drop(watchdog);
assert_eq!(
progress.observations.load(Ordering::SeqCst),
1,
"a run that began executing must stop being supervised after one observation"
);
}
fn shared_authority_with(
current_run: Option<uuid::Uuid>,
turn_phase: mm_dsl::TurnPhase,
runtime_bound: bool,
) -> crate::driver::ephemeral::SharedIngressDslAuthority {
let session_id = meerkat_core::types::SessionId::new();
let authority =
crate::meerkat_machine::dsl_authority::new_registered_authority_without_runtime_entry(
&session_id,
)
.expect("census test authority must register");
let mut state = authority.state().clone();
state.active_runtime_id =
runtime_bound.then(|| mm_dsl::AgentRuntimeId("census-test-runtime".to_string()));
state.active_runtime_generation = runtime_bound.then_some(mm_dsl::Generation(1));
state.current_run_id = current_run.map(|run| mm_dsl::RunId(run.to_string()));
if current_run.is_some() {
state.lifecycle_phase = mm_dsl::MeerkatPhase::Running;
state.pre_run_phase = Some(mm_dsl::PreRunPhase::Attached);
}
state.turn_phase = turn_phase;
Arc::new(std::sync::Mutex::new(
crate::meerkat_machine::recover_projected_authority(
state,
"census test state must recover",
),
))
}
fn armed_window(run: uuid::Uuid, signalled: bool) -> SharedRunStartWindowCell {
let cell = SharedRunStartWindowCell::default();
let turn_start = TurnStartSignalCell::default();
if signalled {
turn_start.mark_signalled();
}
cell.arm(RunId::from_uuid(run), Instant::now(), turn_start);
cell
}
const PAST_BOUND: Duration = Duration::ZERO;
const INSIDE_BOUND: Duration = Duration::MAX;
#[tokio::test]
async fn census_reports_nothing_for_a_session_that_never_staged_a_run() {
let authority = shared_authority_with(
Some(uuid::Uuid::new_v4()),
mm_dsl::TurnPhase::ApplyingPrimitive,
true,
);
assert_eq!(
observe_run_start_window(&SharedRunStartWindowCell::default(), &authority, PAST_BOUND),
RunStartHealth::Clear,
"an unarmed window is not a wedge"
);
}
#[tokio::test]
async fn census_stays_clear_inside_the_notice_bound_even_when_unapplied() {
let run = uuid::Uuid::new_v4();
let authority =
shared_authority_with(Some(run), mm_dsl::TurnPhase::ApplyingPrimitive, true);
assert_eq!(
observe_run_start_window(&armed_window(run, true), &authority, INSIDE_BOUND),
RunStartHealth::Clear,
"a window inside the notice bound is ordinary staging latency, not a wedge"
);
}
#[tokio::test]
async fn census_reports_a_wedged_pre_apply_run_as_overdue() {
let run = uuid::Uuid::new_v4();
let authority =
shared_authority_with(Some(run), mm_dsl::TurnPhase::ApplyingPrimitive, true);
assert_eq!(
observe_run_start_window(&armed_window(run, true), &authority, PAST_BOUND),
RunStartHealth::Overdue,
"a past-bound staged run whose primitive is provably un-applied is the wedge"
);
}
#[tokio::test]
async fn census_never_fires_on_a_stale_window_naming_a_superseded_run() {
let stale_run = uuid::Uuid::new_v4();
let successor_run = uuid::Uuid::new_v4();
let authority = shared_authority_with(
Some(successor_run),
mm_dsl::TurnPhase::ApplyingPrimitive,
true,
);
assert_eq!(
observe_run_start_window(&armed_window(stale_run, true), &authority, PAST_BOUND),
RunStartHealth::Clear,
"a stale window may not convert a successor's fresh staging into a wedge claim"
);
}
#[tokio::test]
async fn census_never_fires_on_a_run_that_began_executing() {
let run = uuid::Uuid::new_v4();
let authority = shared_authority_with(Some(run), mm_dsl::TurnPhase::CallingLlm, true);
assert_eq!(
observe_run_start_window(&armed_window(run, true), &authority, PAST_BOUND),
RunStartHealth::Clear,
"a run that began its turn is slow work, not a staged wedge"
);
}
#[tokio::test]
async fn census_refuses_to_read_leftover_phase_for_an_unsignalled_window() {
let run = uuid::Uuid::new_v4();
let authority =
shared_authority_with(Some(run), mm_dsl::TurnPhase::ApplyingPrimitive, true);
assert_eq!(
observe_run_start_window(&armed_window(run, false), &authority, PAST_BOUND),
RunStartHealth::Unreadable,
"a CURRENT run whose start this read cannot interpret is an absence \
of observation; publishing it as Clear would render 'I cannot see' \
as 'healthy'. Folding this arm to Clear must turn this test red."
);
}
#[tokio::test]
async fn census_clears_an_unsignalled_window_once_its_run_moved_on() {
let stale_run = uuid::Uuid::new_v4();
let authority = shared_authority_with(None, mm_dsl::TurnPhase::Ready, true);
assert_eq!(
observe_run_start_window(&armed_window(stale_run, false), &authority, PAST_BOUND),
RunStartHealth::Clear,
"a window whose run is no longer current is resolved, whatever its signal says"
);
}
#[tokio::test]
async fn census_treats_an_unbound_runtime_as_unobservable_not_overdue() {
let run = uuid::Uuid::new_v4();
let authority = shared_authority_with(None, mm_dsl::TurnPhase::ApplyingPrimitive, false);
assert_eq!(
observe_run_start_window(&armed_window(run, true), &authority, PAST_BOUND),
RunStartHealth::Clear,
"an unbound runtime with the window's run no longer current is a \
resolved window, not a wedge and not an unreadable"
);
}
#[tokio::test]
async fn census_reports_an_unbound_current_run_as_unreadable() {
let run = uuid::Uuid::new_v4();
let authority =
shared_authority_with(Some(run), mm_dsl::TurnPhase::ApplyingPrimitive, false);
assert_eq!(
observe_run_start_window(&armed_window(run, true), &authority, PAST_BOUND),
RunStartHealth::Unreadable,
"a current run whose writes land where this observer cannot see \
has not been proven healthy by anyone"
);
}
#[tokio::test]
async fn census_reports_a_held_authority_as_unreadable_without_blocking() {
let run = uuid::Uuid::new_v4();
let authority =
shared_authority_with(Some(run), mm_dsl::TurnPhase::ApplyingPrimitive, true);
let window = armed_window(run, true);
let guard = authority
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
assert_eq!(
observe_run_start_window(&window, &authority, PAST_BOUND),
RunStartHealth::Unreadable,
"a held authority is unprovable, and the probe must say so rather than wait"
);
drop(guard);
assert_eq!(
observe_run_start_window(&window, &authority, PAST_BOUND),
RunStartHealth::Overdue,
"the same window reads normally once the authority is released"
);
}
#[test]
fn run_start_window_stays_out_of_machine_authority() {
let manifest = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let machine_dir = manifest.join("src/meerkat_machine");
let mut files = vec![
machine_dir.join("dsl.rs"),
machine_dir.join("dsl_authority.rs"),
machine_dir.join("dsl_effects.rs"),
machine_dir.join("composition.rs"),
];
let dispatch_entries =
std::fs::read_dir(&machine_dir).expect("machine authority directory must be readable");
for entry in dispatch_entries {
let path = entry
.expect("machine authority entry must be readable")
.path();
if path
.file_name()
.and_then(|name| name.to_str())
.is_some_and(|name| name.starts_with("dispatch_") && name.ends_with(".rs"))
{
files.push(path);
}
}
let generated_dir = manifest.join("src/generated");
for entry in
std::fs::read_dir(&generated_dir).expect("generated directory must be readable")
{
let path = entry.expect("generated entry must be readable").path();
if path.extension().is_some_and(|ext| ext == "rs") {
files.push(path);
}
}
if let Some(workspace) = manifest.parent() {
let kernels = workspace.join("meerkat-machine-kernels/src/generated/meerkat.rs");
if kernels.exists() {
files.push(kernels);
}
}
let forbidden = [
"run_start_window",
"RunStartWindow",
"RunStartHealth",
"SharedRunStartWindowCell",
"observe_run_start_window",
"overdue_run_start",
"ParkedQueuedWorkHealth",
"ParkedQueuedWorkAxis",
"observe_parked_queued_work",
"parked_queued_work_health",
"parked_queued_input_session_count",
"QUEUED_INPUT_START_NOTICE",
"PARKED_STAGE_CHURN_ATTEMPTS",
];
for file in files {
let source = std::fs::read_to_string(&file)
.unwrap_or_else(|error| panic!("{} must be readable: {error}", file.display()));
for token in forbidden {
assert!(
!source.contains(token),
"{} references `{token}`: the staged-run window is mechanical \
observation for the health census only; a machine-authority or \
dispatch consumer makes it a semantic fact that needs a machine \
owner (see the void condition on SharedRunStartWindowCell)",
file.display()
);
}
}
}
fn parked_census_authority(
registration_active: bool,
current_run: Option<uuid::Uuid>,
inputs: &[(InputId, mm_dsl::InputPhase, u64)],
) -> crate::driver::ephemeral::SharedIngressDslAuthority {
let session_id = meerkat_core::types::SessionId::new();
let authority =
crate::meerkat_machine::dsl_authority::new_registered_authority_without_runtime_entry(
&session_id,
)
.expect("parked census test authority must register");
let mut state = authority.state().clone();
if registration_active {
state.registration_phase = mm_dsl::RegistrationPhase::Active;
}
state.current_run_id = current_run.map(|run| mm_dsl::RunId(run.to_string()));
if current_run.is_some() {
state.lifecycle_phase = mm_dsl::MeerkatPhase::Running;
state.pre_run_phase = Some(mm_dsl::PreRunPhase::Attached);
}
for (input_id, phase, attempts) in inputs {
state.input_phases.insert(input_id.to_string(), *phase);
state
.input_attempt_counts
.insert(input_id.to_string(), *attempts);
if *phase == mm_dsl::InputPhase::Queued {
state
.input_lane
.insert(input_id.to_string(), mm_dsl::InputLane::Queue);
}
}
Arc::new(std::sync::Mutex::new(
crate::meerkat_machine::recover_projected_authority(
state,
"parked census state must recover",
),
))
}
fn parked_census_driver(
rows: &[(
InputId,
chrono::DateTime<chrono::Utc>,
chrono::DateTime<chrono::Utc>,
)],
) -> crate::meerkat_machine::driver::SharedDriver {
let session_id = meerkat_core::types::SessionId::new();
let mut driver = crate::driver::ephemeral::EphemeralRuntimeDriver::new(
crate::identifiers::LogicalRuntimeId::for_session(&session_id),
);
for (input_id, updated_at, created_at) in rows {
let mut state = crate::input_state::InputState::new_accepted(input_id.clone());
state.updated_at = *updated_at;
state.created_at = *created_at;
driver.insert_input_state_for_test(state);
}
Arc::new(crate::tokio::sync::Mutex::new(
crate::meerkat_machine::driver::DriverEntry::Ephemeral(driver),
))
}
const PARKED_NOTICE: Duration = Duration::from_secs(120);
#[test]
fn parked_census_reports_queued_work_past_the_bound() {
let now = chrono::Utc::now();
let input_id = InputId::new();
let authority = parked_census_authority(
true,
None,
&[(input_id.clone(), mm_dsl::InputPhase::Queued, 0)],
);
let driver = parked_census_driver(&[(
input_id,
now - chrono::Duration::seconds(600),
now - chrono::Duration::seconds(600),
)]);
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Parked(ParkedQueuedWorkAxis::AgedInQueue),
"queued work aged past the bound with nothing running is the wedge"
);
}
#[test]
fn parked_census_stays_clear_while_a_run_is_in_flight() {
let now = chrono::Utc::now();
let input_id = InputId::new();
let authority = parked_census_authority(
true,
Some(uuid::Uuid::new_v4()),
&[(input_id.clone(), mm_dsl::InputPhase::Queued, 0)],
);
let driver = parked_census_driver(&[(
input_id,
now - chrono::Duration::seconds(600),
now - chrono::Duration::seconds(600),
)]);
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Clear,
"aged queued work behind a live run must not be read as a wedge"
);
}
#[test]
fn parked_census_stays_clear_without_an_active_registration() {
let now = chrono::Utc::now();
let input_id = InputId::new();
let authority = parked_census_authority(
false,
None,
&[(input_id.clone(), mm_dsl::InputPhase::Queued, 0)],
);
let driver = parked_census_driver(&[(
input_id,
now - chrono::Duration::seconds(600),
now - chrono::Duration::seconds(600),
)]);
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Clear,
"nothing could stage here, so nothing failed to"
);
}
#[test]
fn parked_census_ignores_inputs_outside_the_queued_phase() {
let now = chrono::Utc::now();
let input_id = InputId::new();
let authority = parked_census_authority(
true,
None,
&[(input_id.clone(), mm_dsl::InputPhase::Consumed, 0)],
);
let driver = parked_census_driver(&[(
input_id,
now - chrono::Duration::seconds(600),
now - chrono::Duration::seconds(600),
)]);
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Clear,
"an aged input outside the queued phase is another stage's concern"
);
}
#[test]
fn parked_census_stays_clear_inside_the_notice_bound() {
let now = chrono::Utc::now();
let input_id = InputId::new();
let authority = parked_census_authority(
true,
None,
&[(input_id.clone(), mm_dsl::InputPhase::Queued, 0)],
);
let driver = parked_census_driver(&[(
input_id,
now - chrono::Duration::seconds(30),
now - chrono::Duration::seconds(30),
)]);
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Clear,
"thirty seconds queued is latency, not a wedge"
);
}
#[test]
fn parked_census_never_touches_the_driver_without_queued_work() {
let now = chrono::Utc::now();
let authority = parked_census_authority(true, None, &[]);
let driver = parked_census_driver(&[]);
let held = driver.try_lock().expect("fixture driver is uncontended");
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Clear,
"no queued work means no driver read, held or not"
);
drop(held);
}
#[test]
fn parked_census_skips_a_queued_id_with_no_ledger_row() {
let now = chrono::Utc::now();
let input_id = InputId::new();
let authority =
parked_census_authority(true, None, &[(input_id, mm_dsl::InputPhase::Queued, 0)]);
let driver = parked_census_driver(&[]);
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Clear,
"a phase entry with no ledger clock proves nothing about age"
);
}
#[test]
fn parked_census_reports_a_held_authority_as_unreadable() {
let now = chrono::Utc::now();
let input_id = InputId::new();
let authority = parked_census_authority(
true,
None,
&[(input_id.clone(), mm_dsl::InputPhase::Queued, 0)],
);
let driver = parked_census_driver(&[(
input_id,
now - chrono::Duration::seconds(600),
now - chrono::Duration::seconds(600),
)]);
let guard = authority
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Unreadable,
"a held authority is unprovable, and the probe must say so rather than wait"
);
drop(guard);
}
#[test]
fn parked_census_reports_a_held_driver_as_unreadable() {
let now = chrono::Utc::now();
let input_id = InputId::new();
let authority = parked_census_authority(
true,
None,
&[(input_id.clone(), mm_dsl::InputPhase::Queued, 0)],
);
let driver = parked_census_driver(&[(
input_id,
now - chrono::Duration::seconds(600),
now - chrono::Duration::seconds(600),
)]);
let held = driver.try_lock().expect("fixture driver is uncontended");
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Unreadable,
"a held driver ledger is unprovable, and the probe must not join the queue behind it"
);
drop(held);
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Parked(ParkedQueuedWorkAxis::AgedInQueue),
"the same facts read normally once the driver is released"
);
}
#[test]
fn parked_census_sees_a_stage_churning_input_whose_age_clock_resets() {
let now = chrono::Utc::now();
let input_id = InputId::new();
let authority = parked_census_authority(
true,
None,
&[(
input_id.clone(),
mm_dsl::InputPhase::Queued,
PARKED_STAGE_CHURN_ATTEMPTS,
)],
);
let driver = parked_census_driver(&[(
input_id,
now - chrono::Duration::seconds(5),
now - chrono::Duration::seconds(600),
)]);
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Parked(ParkedQueuedWorkAxis::StageChurn),
"an input staged and thrown back twice, queued again with nothing \
running, is churn - and its re-stamped age clock must not hide it"
);
}
#[test]
fn parked_census_gives_a_young_churning_input_the_notice_floor() {
let now = chrono::Utc::now();
let input_id = InputId::new();
let authority = parked_census_authority(
true,
None,
&[(
input_id.clone(),
mm_dsl::InputPhase::Queued,
PARKED_STAGE_CHURN_ATTEMPTS,
)],
);
let driver = parked_census_driver(&[(
input_id,
now - chrono::Duration::seconds(5),
now - chrono::Duration::seconds(30),
)]);
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Clear,
"thirty seconds of existence is the ordinary bounce window, not churn"
);
}
#[test]
fn parked_census_ignores_a_single_recovered_attempt() {
let now = chrono::Utc::now();
let input_id = InputId::new();
let authority = parked_census_authority(
true,
None,
&[(input_id.clone(), mm_dsl::InputPhase::Queued, 1)],
);
let driver = parked_census_driver(&[(
input_id,
now - chrono::Duration::seconds(5),
now - chrono::Duration::seconds(600),
)]);
assert_eq!(
observe_parked_queued_work(&authority, &driver, PARKED_NOTICE, now),
ParkedQueuedWorkHealth::Clear,
"one attempt and one rollback is an ordinary recovery, not churn"
);
}
}