use super::*;
#[test]
fn classify_meta_loop_variants() {
let tick = parse(
r##"{"type":"user","isMeta":true,"message":{"role":"user","content":"# Autonomous loop tick\nproceed with the next step."}}"##,
);
assert_eq!(
tick.classify(&ClassifyCtx::top_level()),
vec![Class::MetaLoop]
);
let check = parse(
r#"{"type":"user","message":{"role":"user","content":"Run the autonomous check and continue."}}"#,
);
assert_eq!(
check.classify(&ClassifyCtx::top_level()),
vec![Class::MetaLoop]
);
let wake = parse(
r#"{"type":"user","isMeta":true,"message":{"role":"user","content":"<<autonomous-loop-dynamic>>"}}"#,
);
assert_eq!(
wake.classify(&ClassifyCtx::top_level()),
vec![Class::ScheduleWakeup]
);
}
#[test]
fn classify_schedule_wakeup_fired_timer_markers() {
let loop_check = parse(
r##"{"type":"user","isMeta":true,"message":{"role":"user","content":"# Autonomous loop check\n\nYou're being invoked on a timer while the user is away."}}"##,
);
assert_eq!(
loop_check.classify(&ClassifyCtx::top_level()),
vec![Class::ScheduleWakeup]
);
let timer_only = parse(
r#"{"type":"user","isMeta":true,"message":{"role":"user","content":"You're being invoked on a timer to keep work moving."}}"#,
);
assert_eq!(
timer_only.classify(&ClassifyCtx::top_level()),
vec![Class::ScheduleWakeup]
);
}
#[test]
fn loop_markers_anchor_at_content_start() {
let instructions = parse(
r##"{"type":"user","isMeta":true,"message":{"role":"user","content":"# /loop - schedule the autonomous default\n\nThe user invoked /loop with no prompt. Each fire delivers:\n\n# Autonomous loop check\n\nYou're being invoked on a timer while the user is away or occupied."}}"##,
);
assert!(
instructions.classify(&ClassifyCtx::top_level()).is_empty(),
"a record QUOTING the preamble is not the fired tick"
);
let quotes_tick = parse(
r##"{"type":"user","message":{"role":"user","content":"Here is what the driver says:\n\n# Autonomous loop tick\n\nRun the autonomous check using the loop instructions."}}"##,
);
assert_eq!(
quotes_tick.classify(&ClassifyCtx::top_level()),
vec![Class::UserMessage],
"a human quoting the driver keeps user.message"
);
let quotes_sentinel = parse(
r#"{"type":"user","message":{"role":"user","content":"csift models the <<autonomous-loop-dynamic>> sentinel; check the arm order."}}"#,
);
assert_eq!(
quotes_sentinel.classify(&ClassifyCtx::top_level()),
vec![Class::UserMessage]
);
}
#[test]
fn classify_scheduled_fire_prompt() {
let fired = parse(
r#"{"type":"user","uuid":"00000000-0000-4000-8000-000000000011","parentUuid":"00000000-0000-4000-8000-000000000010","isMeta":true,"promptSource":"system","userType":"external","message":{"role":"user","content":"reply with the single word PEONY and nothing else"}}"#,
);
assert_eq!(
fired.classify(&ClassifyCtx::top_level()),
vec![Class::ScheduleFire]
);
let bare_meta = parse(
r#"{"type":"user","isMeta":true,"message":{"role":"user","content":"reply with the single word PEONY and nothing else"}}"#,
);
assert!(bare_meta.classify(&ClassifyCtx::top_level()).is_empty());
let typed = parse(
r#"{"type":"user","promptSource":"typed","message":{"role":"user","content":"reply with the single word PEONY and nothing else"}}"#,
);
assert_eq!(
typed.classify(&ClassifyCtx::top_level()),
vec![Class::UserMessage]
);
let system_no_meta = parse(
r#"{"type":"user","promptSource":"system","message":{"role":"user","content":"reply with the single word PEONY and nothing else"}}"#,
);
assert!(!system_no_meta.is_scheduled_fire_prompt());
assert_eq!(
system_no_meta.classify(&ClassifyCtx::top_level()),
vec![Class::UserMessage]
);
let not_a_user = parse(
r#"{"type":"system","subtype":"informational","isMeta":true,"promptSource":"system","content":"the remote control disconnected"}"#,
);
assert!(!not_a_user.is_scheduled_fire_prompt());
}
#[test]
fn scheduled_fire_refuses_a_peer_message() {
let peer = parse(
r#"{"type":"user","uuid":"00000000-0000-4000-8000-000000000030","isMeta":true,"promptSource":"system","userType":"external","origin":{"kind":"peer","from":"uds:/Users/dev/relay.sock","verifiedPeerPid":4242},"message":{"role":"user","content":"Another Claude session sent a message:\n<cross-session-message from=\"uds:/Users/dev/relay.sock\" from-name=\"relay-7\">\nthe shared resolver landed\n</cross-session-message>\n\nThis came from another Claude session."}}"#,
);
assert_eq!(
peer.classify(&ClassifyCtx::top_level()),
vec![Class::CommInbox]
);
assert!(!peer.is_scheduled_fire_prompt());
let tagless = parse(
r#"{"type":"user","uuid":"00000000-0000-4000-8000-000000000031","isMeta":true,"promptSource":"system","userType":"external","origin":{"kind":"peer","from":"probe-external","verifiedPeerPid":4242},"message":{"role":"user","content":"Another Claude session sent a message:\nreply with exactly PONG\n\nThis came from another Claude session."}}"#,
);
assert!(!tagless.is_scheduled_fire_prompt());
assert!(tagless.classify(&ClassifyCtx::top_level()).is_empty());
}
#[test]
fn a_fired_tick_keeps_its_own_leaf_before_the_fire_arm() {
let check = parse(
r##"{"type":"user","isMeta":true,"promptSource":"system","message":{"role":"user","content":"# Autonomous loop check\n\nYou're being invoked on a timer while the user is away."}}"##,
);
assert_eq!(
check.classify(&ClassifyCtx::top_level()),
vec![Class::ScheduleWakeup]
);
let tick = parse(
r##"{"type":"user","isMeta":true,"promptSource":"system","message":{"role":"user","content":"# Autonomous loop tick\n\nRun the autonomous check using the loop instructions."}}"##,
);
assert_eq!(
tick.classify(&ClassifyCtx::top_level()),
vec![Class::MetaLoop]
);
}
#[test]
fn scheduled_fire_instant_reads_the_parenthesised_tail() {
let cron = parse(
r#"{"type":"system","subtype":"scheduled_task_fire","uuid":"00000000-0000-4000-8000-000000000010","content":"Running scheduled task (Jun 7 5:28am)"}"#,
);
assert!(cron.is_scheduled_task_fire());
assert_eq!(cron.scheduled_fire_instant(), Some("Jun 7 5:28am"));
let wakeup = parse(
r#"{"type":"system","subtype":"scheduled_task_fire","uuid":"00000000-0000-4000-8000-000000000020","content":"Claude resuming /loop wakeup (Jun 7 6:40am)"}"#,
);
assert_eq!(wakeup.scheduled_fire_instant(), Some("Jun 7 6:40am"));
for line in [
r#"{"type":"system","subtype":"scheduled_task_fire","content":"Running scheduled task"}"#,
r#"{"type":"system","subtype":"scheduled_task_fire","content":"Running scheduled task ()"}"#,
r#"{"type":"system","subtype":"scheduled_task_fire","content":{"when":"now"}}"#,
] {
assert_eq!(parse(line).scheduled_fire_instant(), None, "line: {line}");
}
let other = parse(
r#"{"type":"system","subtype":"informational","content":"Running scheduled task (Jun 7 5:28am)"}"#,
);
assert!(!other.is_scheduled_task_fire());
}
#[test]
fn schedule_fire_index_joins_by_parent_uuid() {
let fire = parse(
r#"{"type":"system","subtype":"scheduled_task_fire","uuid":"00000000-0000-4000-8000-000000000010","content":"Running scheduled task (Jun 7 5:28am)"}"#,
);
let no_instant = parse(
r#"{"type":"system","subtype":"scheduled_task_fire","uuid":"00000000-0000-4000-8000-000000000040","content":"Running scheduled task"}"#,
);
let ix = crate::model::ScheduleFireIndex::from_records([&fire, &no_instant].into_iter());
assert_eq!(
ix.instant_for(Some("00000000-0000-4000-8000-000000000010")),
Some("Jun 7 5:28am")
);
assert_eq!(
ix.instant_for(Some("00000000-0000-4000-8000-000000000040")),
None
);
assert_eq!(ix.instant_for(Some("nothing-here")), None);
assert_eq!(ix.instant_for(None), None);
}
#[test]
fn loop_markers_tolerate_leading_whitespace() {
let wake = parse(
r##"{"type":"user","isMeta":true,"message":{"role":"user","content":"\n # Autonomous loop check\n\nYou're being invoked on a timer."}}"##,
);
assert_eq!(
wake.classify(&ClassifyCtx::top_level()),
vec![Class::ScheduleWakeup]
);
let tick = parse(
r##"{"type":"user","isMeta":true,"message":{"role":"user","content":"\n# Autonomous loop tick\n\nproceed."}}"##,
);
assert_eq!(
tick.classify(&ClassifyCtx::top_level()),
vec![Class::MetaLoop]
);
}
#[test]
fn classify_wakeup_check_vs_loop_tick_no_collision() {
let check = parse(
r##"{"type":"user","isMeta":true,"message":{"role":"user","content":"# Autonomous loop check\nproceed."}}"##,
);
assert_eq!(
check.classify(&ClassifyCtx::top_level()),
vec![Class::ScheduleWakeup]
);
let tick = parse(
r##"{"type":"user","isMeta":true,"message":{"role":"user","content":"# Autonomous loop tick\nproceed."}}"##,
);
assert_eq!(
tick.classify(&ClassifyCtx::top_level()),
vec![Class::MetaLoop]
);
let sentinel = parse(
r#"{"type":"user","isMeta":true,"message":{"role":"user","content":"<<autonomous-loop-dynamic>>"}}"#,
);
assert_eq!(
sentinel.classify(&ClassifyCtx::top_level()),
vec![Class::ScheduleWakeup]
);
let run_check = parse(
r#"{"type":"user","isMeta":true,"message":{"role":"user","content":"Run the autonomous check now."}}"#,
);
assert_eq!(
run_check.classify(&ClassifyCtx::top_level()),
vec![Class::MetaLoop]
);
}