use std::io;
use bamboo_domain::{
ActorDirectoryEntry, ProjectId, ScopedLoopControlBinding, Session, SessionKind,
AGENT_RUNTIME_STATE_VERSION,
};
use chrono::{DateTime, Utc};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum ScopedNativeTransportDisposition {
LiveOrUnknown,
Inert(ScopedNativeTransportInertReason),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum ScopedNativeTransportInertReason {
CurrentActivationTerminal,
CurrentLeaseExpired,
OwnerRunSuperseded,
PipelineExecutionSuperseded,
}
pub(super) fn scoped_native_transport_disposition(
binding: &ScopedLoopControlBinding,
canonical: &Session,
entry: &ActorDirectoryEntry,
now: DateTime<Utc>,
) -> io::Result<ScopedNativeTransportDisposition> {
use ScopedNativeTransportDisposition::{Inert, LiveOrUnknown};
use ScopedNativeTransportInertReason::{
CurrentActivationTerminal, CurrentLeaseExpired, OwnerRunSuperseded,
PipelineExecutionSuperseded,
};
let invalid = |message| io::Error::new(io::ErrorKind::InvalidData, message);
binding
.validate()
.map_err(|_| invalid("invalid scoped transport selector"))?;
entry
.validate()
.map_err(|_| invalid("invalid current native census"))?;
let project: Option<ProjectId> = canonical
.project_id_meta()
.map(ProjectId::parse)
.transpose()
.map_err(|_| invalid("invalid current native Project"))?;
if canonical.id != binding.target_session_id
|| canonical.created_at != binding.target_created_at
|| canonical.kind != SessionKind::Root
|| canonical.parent_session_id.is_some()
|| canonical.spawn_depth != 0
|| !canonical.authority_identity.is_ordinary()
|| !entry.actor.matches_session(canonical)
|| entry.actor.project_id.as_deref() != project.as_ref().map(ProjectId::as_str)
{
return Err(invalid("native census/canonical target lifetime mismatch"));
}
if let Some(runtime) = canonical.agent_runtime_state.as_ref() {
if runtime.version != AGENT_RUNTIME_STATE_VERSION
|| runtime
.execution_id
.as_deref()
.is_some_and(|id| !bamboo_domain::valid_session_run_id(id))
{
return Err(invalid("invalid current canonical runtime identity"));
}
}
let Some(current) = entry.activation.as_ref() else {
return Ok(LiveOrUnknown);
};
if !current.status.is_live() {
return Ok(Inert(CurrentActivationTerminal));
}
if current.lease_expires_at <= now {
return Ok(Inert(CurrentLeaseExpired));
}
if current.run_id != binding.owner_run_id {
return Ok(Inert(OwnerRunSuperseded));
}
if canonical
.agent_runtime_state
.as_ref()
.and_then(|runtime| runtime.execution_id.as_deref())
.is_some_and(|execution| execution != binding.execution_id)
{
return Ok(Inert(PipelineExecutionSuperseded));
}
Ok(LiveOrUnknown)
}