use chrono::{DateTime, Utc};
use trusty_common::memory_core::decay::DecayConfig;
use trusty_common::memory_core::palace::Drawer;
const DATE_SCAN_CHARS: usize = 120;
const WEIGHT_RETAINED_MIN_AGE_DAYS: f32 = 14.0;
const WEIGHT_RETAINED_FRACTION: f32 = 0.8;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Signal {
Tagged(String),
DateStamped,
MaxImportance,
NoExpiry,
WeightRetained,
PredatesLogWindow,
}
impl Signal {
pub fn label(&self) -> String {
match self {
Signal::Tagged(t) => format!("tag:{t}"),
Signal::DateStamped => "date-stamped".to_string(),
Signal::MaxImportance => "importance=1.0".to_string(),
Signal::NoExpiry => "no-expiry".to_string(),
Signal::WeightRetained => "weight-retained".to_string(),
Signal::PredatesLogWindow => "predates-log-window".to_string(),
}
}
}
const REPORTED_TAGS: [&str; 4] = [
"status",
"resume-target",
"standing-instruction",
"bob-decision",
];
pub fn observe(drawer: &Drawer, age_days: f32, window_start: Option<DateTime<Utc>>) -> Vec<Signal> {
let mut out = Vec::new();
for tag in REPORTED_TAGS {
if drawer.tags.iter().any(|t| t == tag) {
out.push(Signal::Tagged(tag.to_string()));
}
}
if opens_with_date(drawer.content()) {
out.push(Signal::DateStamped);
}
if drawer.importance >= 1.0 {
out.push(Signal::MaxImportance);
}
if drawer.expires_at.is_none() {
out.push(Signal::NoExpiry);
}
let decayed = DecayConfig::default().effective_importance(drawer.importance, age_days, 0.0);
if age_days >= WEIGHT_RETAINED_MIN_AGE_DAYS
&& drawer.importance > 0.0
&& decayed / drawer.importance >= WEIGHT_RETAINED_FRACTION
{
out.push(Signal::WeightRetained);
}
if window_start.is_some_and(|start| drawer.created_at < start) {
out.push(Signal::PredatesLogWindow);
}
out
}
fn opens_with_date(content: &str) -> bool {
let head: Vec<char> = content.chars().take(DATE_SCAN_CHARS).collect();
head.windows(10).any(|w| {
w[0..4].iter().all(char::is_ascii_digit)
&& w[4] == '-'
&& w[5..7].iter().all(char::is_ascii_digit)
&& w[7] == '-'
&& w[8..10].iter().all(char::is_ascii_digit)
})
}