use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;
pub(crate) static PENDING: AtomicBool = AtomicBool::new(false);
static LEDGER: Mutex<Vec<(String, String)>> = Mutex::new(Vec::new());
pub fn record_config_locked(key: &'static str, value: impl Into<String>) {
LEDGER
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
.push((key.to_string(), value.into()));
PENDING.store(true, Ordering::Release);
}
pub(crate) fn drain_config_locked() -> Vec<(String, String)> {
std::mem::take(
&mut *LEDGER
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner()),
)
}
#[cfg(test)]
pub(crate) fn has_pending_config_locked() -> bool {
PENDING.load(Ordering::Acquire)
}
#[cfg(test)]
mod tests {
use super::*;
use serial_test::serial;
#[test]
#[serial(config_ledger)]
fn record_then_drain_returns_queued_pairs_in_order() {
drain_config_locked(); PENDING.store(false, Ordering::Release);
assert!(!has_pending_config_locked());
record_config_locked("recall_profile_enabled", "true");
record_config_locked("ann_overfetch_max_rounds", "3");
assert!(has_pending_config_locked());
let drained = drain_config_locked();
assert_eq!(
drained,
vec![
("recall_profile_enabled".to_string(), "true".to_string()),
("ann_overfetch_max_rounds".to_string(), "3".to_string()),
]
);
}
#[test]
#[serial(config_ledger)]
fn dispatch_fast_path_drains_exactly_once_then_reports_no_pending() {
drain_config_locked();
PENDING.store(false, Ordering::Release);
record_config_locked("context_profile_enabled", "false");
assert!(PENDING.swap(false, Ordering::AcqRel));
let drained = drain_config_locked();
assert_eq!(
drained,
vec![("context_profile_enabled".to_string(), "false".to_string())]
);
assert!(
!PENDING.swap(false, Ordering::AcqRel),
"a second dispatch must observe the flag already cleared"
);
assert!(
drain_config_locked().is_empty(),
"nothing should be left to re-emit on a later dispatch"
);
}
}