//! A failed heartbeat turn still advances `last_heartbeat`. Do not edit. mod support; use bxcore::Timestamp; use loopd::channel::Context; use loopd::llama::Client; use loopd::memory::NoMemory; use loopd::scheduler::{Scheduler, TickWork}; use loopd::tools::Registry; use std::sync::Arc; use support::{FakeServer, Home, Reply, ScriptedPort}; const CHAT: &str = "/v1/chat/completions"; const PROMPT: &str = "Look around.\n"; fn ts(s: &str) -> Timestamp { Timestamp::parse(s).unwrap() } fn world() -> (Home, FakeServer, Arc) { let home = Home::new(); home.write("heartbeat.md", PROMPT); home.write("compact.md", "Summarise.\n"); let server = FakeServer::start(); let mut cfg = home.config(&server.socket); cfg.heartbeat.every_s = 60; cfg.heartbeat.prompt = home.dir.join("heartbeat.md"); server.route(CHAT, vec![Reply::fixture("bad_request")]); let ctx = Arc::new(Context::new( cfg.clone(), Client::new(cfg), Box::new(ScriptedPort::new(vec![])), Registry::m2b(), Box::new(NoMemory), )); (home, server, ctx) } #[test] fn a_failed_heartbeat_turn_still_advances_last_heartbeat() { let (_home, server, ctx) = world(); let mut sched = Scheduler::new(ts("2026-10-03T07:00:00.000Z")); let work = sched.tick(&ctx, ts("2026-10-03T07:01:00.000Z")); assert_eq!(work, vec![TickWork::Heartbeat]); assert_eq!(server.requests_to(CHAT).len(), 1); let work = sched.tick(&ctx, ts("2026-10-03T07:01:30.000Z")); assert!(work.is_empty(), "{work:?}"); assert_eq!(server.requests_to(CHAT).len(), 1); }