use super::caller::GateVerdict;
use super::{Mode, Relation, SenderKind, Verdict};
pub(crate) const OFFICIAL_FLOOR: (u32, u32, u32) = (2, 1, 198);
pub(crate) const CH_MAILBOX: &str = "official mailbox";
pub(crate) const CH_IN_PROCESS: &str = "official in-process queue";
pub(crate) const CH_UDS: &str = "official uds";
pub(crate) const CH_RESUME: &str = "official resume";
pub(crate) const CH_STEER: &str = "csift steer";
pub(crate) const CH_QUEUE: &str = "csift queue";
pub(crate) const CH_NONE: &str = "none";
const OFFICIAL_TOOL: &str = "SendMessage";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ReceiverKind {
TopLevel,
UnnamedSubagent,
Teammate,
WorkflowLane,
}
impl ReceiverKind {
pub(crate) fn as_str(self) -> &'static str {
match self {
ReceiverKind::TopLevel => "top-level session",
ReceiverKind::UnnamedSubagent => "unnamed subagent",
ReceiverKind::Teammate => "teammate",
ReceiverKind::WorkflowLane => "workflow lane",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ReceiverState {
Running,
Frozen,
Completed,
StoppedByUser,
Dead,
Unknown,
}
impl ReceiverState {
pub(crate) fn as_str(self) -> &'static str {
match self {
ReceiverState::Running => "running",
ReceiverState::Frozen => "frozen",
ReceiverState::Completed => "completed",
ReceiverState::StoppedByUser => "stopped-by-user",
ReceiverState::Dead => "dead",
ReceiverState::Unknown => "unknown",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct OfficialCall {
pub(crate) tool: &'static str,
pub(crate) to: Option<String>,
pub(crate) call: String,
}
impl OfficialCall {
fn addressed(to: &str) -> Self {
OfficialCall {
tool: OFFICIAL_TOOL,
to: Some(to.to_string()),
call: format!("{OFFICIAL_TOOL}(to: \"{to}\", message: <this message>)"),
}
}
fn unaddressable() -> Self {
OfficialCall {
tool: OFFICIAL_TOOL,
to: None,
call: format!(
"{OFFICIAL_TOOL}(to: <the peer as your harness names it>, message: <this \
message>) - the official `to` grammar has no bare-uuid arm, so the receiver's \
session uuid is not a legal value and csift will not invent one"
),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct SendContext {
pub(crate) caller_kind: SenderKind,
pub(crate) caller_is_subagent: bool,
pub(crate) relation: Relation,
pub(crate) receiver_kind: ReceiverKind,
pub(crate) receiver_state: ReceiverState,
pub(crate) receiver_version: Option<String>,
pub(crate) headless: bool,
pub(crate) socket_present: bool,
pub(crate) lane: String,
pub(crate) routing_id: Option<String>,
pub(crate) mode: Mode,
pub(crate) queues: bool,
pub(crate) resume: bool,
pub(crate) official_only: bool,
pub(crate) teams: GateVerdict,
pub(crate) harbor: GateVerdict,
pub(crate) chunks: usize,
pub(crate) best_slots: usize,
pub(crate) best_event: Option<String>,
pub(crate) armed: usize,
pub(crate) async_rewake_on_stop: bool,
pub(crate) hooks_policy_switch: Option<String>,
}
impl SendContext {
pub(crate) fn official_possible(&self) -> bool {
self.receiver_version
.as_deref()
.and_then(parse_version)
.is_some_and(|v| v >= OFFICIAL_FLOOR)
}
fn alive(&self) -> bool {
matches!(
self.receiver_state,
ReceiverState::Running | ReceiverState::Frozen
)
}
}
#[derive(Debug, Clone)]
pub(crate) struct Decision {
pub(crate) channel: &'static str,
pub(crate) verdict: Verdict,
pub(crate) prediction: String,
pub(crate) risks: Vec<String>,
pub(crate) official: Option<OfficialCall>,
pub(crate) queued: bool,
}
pub(crate) fn decide(ctx: &SendContext) -> Decision {
let mut d = route(ctx);
if d.verdict == Verdict::Refused {
d.queued = false;
return d;
}
if ctx.official_only && d.official.is_some() {
d.queued = false;
}
let delegated_risks = d.risks.len();
collect_risks(ctx, &mut d);
d.verdict = verdict_for(ctx, &d, delegated_risks);
if d.queued {
d.prediction = format!("{} {}", d.prediction, csift_leg(ctx));
}
d
}
fn route(ctx: &SendContext) -> Decision {
if ctx.receiver_state == ReceiverState::StoppedByUser {
return refused(
"the receiver lane was stopped by the user - the harness refuses a resume for this \
state and instructs a sender to treat the work as cancelled, so csift queues \
nothing it could never deliver",
);
}
match ctx.receiver_kind {
ReceiverKind::WorkflowLane => workflow_row(ctx),
ReceiverKind::TopLevel => top_level_row(ctx),
ReceiverKind::Teammate | ReceiverKind::UnnamedSubagent => agent_row(ctx),
}
}
fn workflow_row(ctx: &SendContext) -> Decision {
if matches!(
ctx.receiver_state,
ReceiverState::Completed | ReceiverState::Dead
) {
return refused(
"a completed workflow lane has no re-entry point: an official resume by its id \
resolves to a transcript path the lane never wrote to, and no hook fires in a \
lane that has ended",
);
}
Decision {
channel: csift_channel(ctx),
verdict: Verdict::Ok,
prediction: "the csift channel is the only carrier for a workflow lane: the official \
send fails closed on it."
.to_string(),
risks: Vec::new(),
official: None,
queued: true,
}
}
fn top_level_row(ctx: &SendContext) -> Decision {
if ctx.headless {
return Decision {
channel: csift_channel(ctx),
verdict: Verdict::Unpredictable,
prediction: "the receiver is a headless run: csift never promises delivery to one."
.to_string(),
risks: vec![
"the registry row's entrypoint is `sdk-cli`: a headless receiver has no \
approval surface for an inbound message and may end before any hook point \
is reached"
.to_string(),
],
official: None,
queued: true,
};
}
if ctx.caller_kind == SenderKind::Lane && ctx.socket_present && ctx.official_possible() {
return Decision {
channel: CH_UDS,
verdict: Verdict::Ok,
prediction: "the receiver published a messaging socket, so the official \
cross-session send reaches it directly."
.to_string(),
risks: vec![
"the official inbound message can be HELD for approval when the receiver's \
permission mode is bypass-class, and it is enqueued at the receiver's MAIN \
lane - a reply cannot come back to a subagent"
.to_string(),
],
official: Some(OfficialCall::unaddressable()),
queued: true,
};
}
let mut risks = Vec::new();
if !ctx.socket_present && !ctx.async_rewake_on_stop {
risks.push(
"no messaging socket in the registry and no `asyncRewake` hook on Stop: nothing \
wakes an idle top-level session, so the message waits for its human"
.to_string(),
);
}
Decision {
channel: csift_channel(ctx),
verdict: Verdict::Ok,
prediction: "no official arm is available for this receiver, so the csift channel \
carries it."
.to_string(),
risks,
official: None,
queued: true,
}
}
fn agent_row(ctx: &SendContext) -> Decision {
if ctx.receiver_state == ReceiverState::Completed {
return completed_agent_row(ctx);
}
if ctx.caller_kind == SenderKind::External || !ctx.official_possible() {
return csift_only(ctx);
}
if ctx.caller_is_subagent
&& ctx.relation == Relation::Child
&& ctx.receiver_kind == ReceiverKind::UnnamedSubagent
{
return Decision {
channel: csift_channel(ctx),
verdict: Verdict::Ok,
prediction: "the official channel has no parent arm: addressing `main` reaches the \
top-level conversation, not the spawning agent, so the csift channel \
is the only carrier to a parent subagent."
.to_string(),
risks: Vec::new(),
official: None,
queued: true,
};
}
match ctx.receiver_kind {
ReceiverKind::Teammate if ctx.teams.enabled => Decision {
channel: CH_MAILBOX,
verdict: Verdict::Ok,
prediction: "the teammate mailbox is the official arm and the receiver polls it \
itself."
.to_string(),
risks: vec![
"a mailbox entry is DELETED when the receiver consumes it and its `read` flag \
is never flipped, so only the entry's disappearance joined to a record in \
the receiver's transcript proves delivery"
.to_string(),
],
official: Some(OfficialCall::addressed(official_to(ctx))),
queued: true,
},
ReceiverKind::Teammate => csift_only(ctx),
_ => Decision {
channel: CH_IN_PROCESS,
verdict: Verdict::Ok,
prediction: "the in-process queue is the official arm for a running unnamed \
subagent."
.to_string(),
risks: vec![
"the official queue returns that a task record EXISTS, never that the message \
was delivered; the target must be addressed by its `a...` id, and the send \
is attributed to the session rather than to the calling lane"
.to_string(),
],
official: Some(OfficialCall::addressed(official_to(ctx))),
queued: true,
},
}
}
fn official_to(ctx: &SendContext) -> &str {
ctx.routing_id.as_deref().unwrap_or(&ctx.lane)
}
fn completed_agent_row(ctx: &SendContext) -> Decision {
if !ctx.official_possible() {
return refused(
"the receiver lane has completed and its Claude Code version is below the official \
floor, so no resume path exists for it and a csift delivery would wait for a hook \
point that will never come",
);
}
if !ctx.resume {
return refused(
"the receiver lane has completed: reaching it is an official RESUME, which \
respawns the lane rather than delivering to it. Pass --resume to delegate that \
resume, or address a running lane instead",
);
}
Decision {
channel: CH_RESUME,
verdict: Verdict::Ok,
prediction: "this respawns the lane with its prior messages replayed; on Claude Code \
below 2.1.260 its completion notification goes to the main conversation, \
not to you."
.to_string(),
risks: vec![
"a resume is an action, not a delivery: the lane is respawned, and a concurrent \
resume of the same lane throws rather than queueing"
.to_string(),
"with background tasks disabled, or against the built-in web-fetch agent, the \
resume runs INLINE: no completion notification is enqueued at all and the report \
comes back inside the tool result instead"
.to_string(),
],
official: Some(OfficialCall::addressed(official_to(ctx))),
queued: true,
}
}
fn csift_only(ctx: &SendContext) -> Decision {
let why = if ctx.caller_kind == SenderKind::External {
"the caller is outside Claude Code and holds no tool to call, so the csift channel is \
the only carrier."
} else if !ctx.official_possible() {
"the receiver is below the official floor for any official send path, so the csift \
channel is the only carrier."
} else {
"no official arm is provable from disk for this receiver, so the csift channel carries \
it."
};
Decision {
channel: csift_channel(ctx),
verdict: Verdict::Ok,
prediction: why.to_string(),
risks: Vec::new(),
official: None,
queued: true,
}
}
fn refused(reason: &str) -> Decision {
Decision {
channel: CH_NONE,
verdict: Verdict::Refused,
prediction: reason.to_string(),
risks: Vec::new(),
official: None,
queued: false,
}
}
fn csift_channel(ctx: &SendContext) -> &'static str {
match ctx.mode {
Mode::Steer => CH_STEER,
Mode::Queue => CH_QUEUE,
}
}
fn csift_leg(ctx: &SendContext) -> String {
let event = ctx.best_event.as_deref().unwrap_or("no configured event");
let lead = if ctx.queues {
"csift queued it too:"
} else {
"csift would queue it too:"
};
match ctx.mode {
Mode::Steer => format!(
"{lead} the next `csift deliver` hook to run in this lane emits part 1 ({} of {} \
chunk(s) fit at {event}).",
ctx.best_slots.min(ctx.chunks),
ctx.chunks
),
Mode::Queue => format!(
"{lead} delivery waits for a turn boundary ({} of {} chunk(s) fit at {event}).",
ctx.best_slots.min(ctx.chunks),
ctx.chunks
),
}
}
fn collect_risks(ctx: &SendContext, d: &mut Decision) {
if !d.queued {
return;
}
if let Some(switch) = &ctx.hooks_policy_switch {
d.risks.push(format!(
"a policy switch rewrote the receiver's hook set ({switch}), so a configured \
delivery hook may never run"
));
}
if ctx.best_slots == 0 {
d.risks.push(
"no `csift deliver --slot k` hook is configured on any delivery event in the \
receiver's settings cascade: the message stays queued until one is installed"
.to_string(),
);
} else if ctx.armed == 0 {
d.risks.push(
"the delivery slots are CONFIGURED but none has ever run in this lane (no armed \
marker): configuration is not arming - the receiver's process may predate the \
settings edit"
.to_string(),
);
}
if ctx.receiver_state == ReceiverState::Frozen {
d.risks.push(
"the receiver lane is frozen at an unreturned tool call: its next hook point comes \
only when that call returns"
.to_string(),
);
}
if ctx.receiver_kind == ReceiverKind::Teammate && !ctx.teams.enabled {
d.risks.push(format!("teams gate: {}", ctx.teams.verdict));
}
}
fn verdict_for(ctx: &SendContext, d: &Decision, delegated_risks: usize) -> Verdict {
if d.verdict == Verdict::Refused {
return Verdict::Refused;
}
if !d.queued {
return Verdict::Ok;
}
if ctx.best_slots == 0 || !ctx.alive() || ctx.headless {
return Verdict::Unpredictable;
}
if ctx.chunks > ctx.best_slots {
return Verdict::Full;
}
if d.risks.len() > delegated_risks {
Verdict::MayFail
} else {
Verdict::Ok
}
}
pub(crate) fn full_note(ctx: &SendContext) -> String {
format!(
"{} chunk(s) against {} configured slot(s) at {}: {} more slot(s) on one delivery \
event would carry the whole message in one hook round",
ctx.chunks,
ctx.best_slots,
ctx.best_event.as_deref().unwrap_or("no configured event"),
ctx.chunks.saturating_sub(ctx.best_slots)
)
}
pub(crate) fn parse_version(s: &str) -> Option<(u32, u32, u32)> {
let mut it = s.trim().split('.');
let a = it.next()?.parse().ok()?;
let b = it.next()?.parse().ok()?;
let c = it.next()?.parse().ok()?;
it.next().is_none().then_some((a, b, c))
}