use lean_ctx::core::knowledge::{FactValidity, KnowledgeFact, ProjectKnowledge};
pub(crate) fn recall_section(
reader_root: &str,
category: Option<&str>,
query: Option<&str>,
limit: usize,
) -> Option<String> {
let (link, checkouts) = lean_ctx::core::project_link::linked_checkouts(reader_root)?;
let terms: Vec<String> = query
.map(str::to_lowercase)
.unwrap_or_default()
.split_whitespace()
.map(str::to_owned)
.collect();
let matches = |fact: &KnowledgeFact| {
category.is_none_or(|category| fact.category.eq_ignore_ascii_case(category))
&& (terms.is_empty() || {
let text = format!("{} {} {}", fact.category, fact.key, fact.value).to_lowercase();
terms.iter().any(|term| text.contains(term.as_str()))
})
};
let mut served: Vec<(String, KnowledgeFact)> = Vec::new();
let mut stale = 0usize;
for checkout in checkouts {
let Some(knowledge) = lean_ctx::core::policy::runtime::REQUEST_PROJECT.sync_scope(
std::cell::RefCell::new(Some(std::path::PathBuf::from(&checkout))),
|| ProjectKnowledge::load(&checkout),
) else {
continue;
};
for fact in knowledge
.facts
.into_iter()
.filter(KnowledgeFact::is_current)
{
if !matches(&fact) {
continue;
}
match fact.validity {
Some(FactValidity::Convention) => {
lean_ctx::core::context_admission::stored::publish_served(None);
served.push((knowledge.project_root.clone(), fact));
}
Some(FactValidity::Content) => {
let item = lean_ctx::core::archive::bindings::Item::KnowledgeFact {
project: &knowledge.project_root,
category: &fact.category,
key: &fact.key,
};
if lean_ctx::core::archive::bindings::holds_in_checkout(
&item,
&fact.value,
reader_root,
) {
served.push((knowledge.project_root.clone(), fact));
} else {
stale += 1;
}
}
None => {}
}
}
}
if served.is_empty() && stale == 0 {
return None;
}
served.sort_by(|a, b| {
(a.0.as_str(), a.1.category.as_str(), a.1.key.as_str()).cmp(&(
b.0.as_str(),
b.1.category.as_str(),
b.1.key.as_str(),
))
});
served.truncate(limit);
let mut out = format!(
"Linked checkouts of project '{}' (served by validity class):\n",
link.team_project_id
);
for (checkout, fact) in &served {
out.push_str(&format!(
" [{}/{}]: {} [{}] (checkout: {})\n",
fact.category,
fact.key,
fact.as_delivered(fact.value.clone()),
fact.validity.map_or("", FactValidity::as_str),
super::short_path(checkout),
));
}
if stale > 0 {
out.push_str(&format!(
" {stale} code-bound fact(s) withheld: stale — their sources differ in this checkout (next: refresh_source)\n"
));
}
Some(out)
}