use crate::core::context_field::{ContextItemId, ContextState};
use crate::core::context_ledger::{ContextLedger, PressureAction};
use crate::core::context_overlay::{OverlayOp, OverlayStore};
fn is_precise_pinned_mode(requested_mode: &str) -> bool {
requested_mode
.parse::<crate::tools::ctx_read::ReadMode>()
.is_ok_and(|m| m.is_precise_pinned_read())
}
#[derive(Debug, Clone)]
pub struct PreDispatchResult {
pub overridden_mode: Option<String>,
pub reason: Option<&'static str>,
pub pressure_downgraded: bool,
pub budget_blocked: bool,
pub budget_warning: Option<String>,
pub triage_filter_level: u8,
}
#[derive(Debug, Clone)]
pub struct PostDispatchResult {
pub eviction_hint: Option<String>,
pub elicitation_hint: Option<String>,
pub resource_changed: bool,
pub prefetch_hint: Option<String>,
}
pub fn knowledge_advice(
query: &str,
) -> crate::core::knowledge_router::gate_integration::KnowledgeAdvice {
let current = crate::core::context_kernel::ContextState::new(
Vec::new(),
crate::core::knowledge::KnowledgeQuery::default(),
);
crate::core::knowledge_router::gate_integration::KnowledgeGateAdvisor::advise(query, ¤t)
}
pub fn pre_dispatch_read(
path: &str,
requested_mode: &str,
task: Option<&str>,
project_root: Option<&str>,
pressure: Option<&PressureAction>,
) -> PreDispatchResult {
pre_dispatch_read_for_agent(path, requested_mode, task, project_root, pressure, None)
}
pub fn pre_dispatch_read_for_agent(
path: &str,
requested_mode: &str,
task: Option<&str>,
project_root: Option<&str>,
pressure: Option<&PressureAction>,
agent_id: Option<&str>,
) -> PreDispatchResult {
let no_change = PreDispatchResult {
overridden_mode: None,
reason: None,
pressure_downgraded: false,
budget_blocked: false,
budget_warning: None,
triage_filter_level: 0,
};
if let Some(aid) = agent_id {
let estimated_tokens = estimate_read_tokens(path, requested_mode);
match crate::core::agent_budget::check_budget(aid, estimated_tokens) {
crate::core::agent_budget::BudgetCheckResult::Exceeded { limit, consumed } => {
return PreDispatchResult {
overridden_mode: None,
reason: Some("agent-budget-exceeded"),
pressure_downgraded: false,
budget_blocked: true,
budget_warning: Some(format!(
"Agent budget exceeded: {consumed}/{limit} tokens consumed. Reset via ctx_session or set a higher limit."
)),
triage_filter_level: 0,
};
}
crate::core::agent_budget::BudgetCheckResult::Warning {
remaining,
percent_used,
} => {
let warning = format!(
"[BUDGET WARNING] Agent '{aid}' at {:.0}% budget ({remaining} tokens remaining)",
percent_used * 100.0
);
let mut result = no_change.clone();
result.budget_warning = Some(warning);
if is_precise_pinned_mode(requested_mode) {
return result;
}
let rest = pre_dispatch_inner(path, requested_mode, task, project_root, pressure);
return PreDispatchResult {
budget_warning: result.budget_warning,
..rest
};
}
crate::core::agent_budget::BudgetCheckResult::Allowed { .. } => {}
}
}
pre_dispatch_inner(path, requested_mode, task, project_root, pressure)
}
fn pre_dispatch_inner(
path: &str,
requested_mode: &str,
task: Option<&str>,
project_root: Option<&str>,
pressure: Option<&PressureAction>,
) -> PreDispatchResult {
let no_change = PreDispatchResult {
overridden_mode: None,
reason: None,
pressure_downgraded: false,
budget_blocked: false,
budget_warning: None,
triage_filter_level: 0,
};
if is_precise_pinned_mode(requested_mode) {
return no_change;
}
if let Some(root) = project_root {
let overlay = OverlayStore::load_project(&std::path::PathBuf::from(root));
if let Some(result) = check_overlay_mode_override(path, requested_mode, &overlay) {
return result;
}
}
if requested_mode == "full" {
return no_change;
}
if let Some(action) = pressure {
let no_degrade = crate::core::config::Config::load().no_degrade_effective();
let profile = crate::core::profiles::active_profile();
if !no_degrade
&& profile.degradation.enforce_effective()
&& let Some(downgraded) = pressure_downgrade(requested_mode, action)
{
return PreDispatchResult {
overridden_mode: Some(downgraded),
reason: Some("pressure-auto-downgrade"),
pressure_downgraded: true,
budget_blocked: false,
budget_warning: None,
triage_filter_level: 0,
};
}
}
if let Ok(bt) = crate::core::bounce_tracker::global().lock()
&& bt.should_force_full(path)
{
return PreDispatchResult {
overridden_mode: Some("full".to_string()),
reason: Some("bounce-prevention"),
pressure_downgraded: false,
budget_blocked: false,
budget_warning: None,
triage_filter_level: 0,
};
}
if let Some(task_str) = task {
let intent = crate::core::intent_engine::StructuredIntent::from_query(task_str);
let norm = crate::core::pathutil::normalize_tool_path(path);
let is_target = intent
.targets
.iter()
.any(|t| norm.ends_with(t) || norm.contains(t));
if is_target {
return PreDispatchResult {
overridden_mode: Some("full".to_string()),
reason: Some("intent-target"),
pressure_downgraded: false,
budget_blocked: false,
budget_warning: None,
triage_filter_level: 0,
};
}
}
if let Some(root) = project_root
&& let Some(open) = try_load_graph(root)
{
let gp = &open.provider;
let related = gp.related(path, 1);
if let Some(task_str) = task {
let intent = crate::core::intent_engine::StructuredIntent::from_query(task_str);
for target in &intent.targets {
let target_related = gp.related(target, 1);
let norm = crate::core::pathutil::normalize_tool_path(path);
if target_related
.iter()
.any(|r| r.contains(&norm) || norm.contains(r))
{
return PreDispatchResult {
overridden_mode: Some("map".to_string()),
reason: Some("graph-direct-import"),
pressure_downgraded: false,
budget_blocked: false,
budget_warning: None,
triage_filter_level: 0,
};
}
}
}
if !related.is_empty() && requested_mode == "auto" {
let reverse_deps = gp.dependents(path);
if reverse_deps.len() > 3 {
return PreDispatchResult {
overridden_mode: Some("map".to_string()),
reason: Some("graph-hub-file"),
pressure_downgraded: false,
budget_blocked: false,
budget_warning: None,
triage_filter_level: 0,
};
}
}
}
if let Some(root) = project_root
&& let Some(knowledge) = crate::core::knowledge::ProjectKnowledge::load(root)
{
let norm = crate::core::pathutil::normalize_tool_path(path);
let mentions = knowledge
.facts
.iter()
.filter(|f| f.value.contains(&norm) || f.key.contains(&norm))
.count();
if mentions >= 3 {
return PreDispatchResult {
overridden_mode: Some("map".to_string()),
reason: Some("knowledge-high-relevance"),
pressure_downgraded: false,
budget_blocked: false,
budget_warning: None,
triage_filter_level: 0,
};
}
}
no_change
}
fn estimate_read_tokens(path: &str, mode: &str) -> usize {
let file_size = std::fs::metadata(path).map_or(4000, |m| m.len() as usize);
let char_estimate = file_size;
let full_tokens = char_estimate / 4;
match mode {
"signatures" => full_tokens / 5,
"map" => full_tokens / 3,
"aggressive" | "entropy" => full_tokens / 4,
"diff" => full_tokens / 10,
_ if mode.starts_with("lines:") => {
if let Some(range) = mode.strip_prefix("lines:") {
let mut selected = 0usize;
for part in range.split(',') {
let part = part.trim();
selected += if let Some((s, e)) = part.split_once('-') {
let start = s.trim().parse::<usize>().unwrap_or(1);
let end = e.trim().parse::<usize>().unwrap_or(start + 100);
end.saturating_sub(start) + 1
} else {
1
};
}
if selected == 0 {
full_tokens / 10
} else {
selected * 10
}
} else {
full_tokens / 10
}
}
_ => full_tokens,
}
}
fn pressure_downgrade(requested_mode: &str, action: &PressureAction) -> Option<String> {
crate::core::auto_mode_resolver::pressure_downgrade(requested_mode, action)
}
fn check_overlay_mode_override(
path: &str,
requested_mode: &str,
overlay: &OverlayStore,
) -> Option<PreDispatchResult> {
let item_id = ContextItemId::from_file(path);
let overlays = overlay.for_item(&item_id);
for ov in overlays.iter().rev() {
match &ov.operation {
OverlayOp::SetView(view) => {
let mode_str = view.as_str();
if mode_str != requested_mode {
return Some(PreDispatchResult {
overridden_mode: Some(mode_str.to_string()),
reason: Some("overlay-set-view"),
pressure_downgraded: false,
budget_blocked: false,
budget_warning: None,
triage_filter_level: 0,
});
}
}
OverlayOp::Pin { .. } if requested_mode != "full" => {
return Some(PreDispatchResult {
overridden_mode: Some("full".to_string()),
reason: Some("pinned"),
pressure_downgraded: false,
budget_blocked: false,
budget_warning: None,
triage_filter_level: 0,
});
}
OverlayOp::Exclude { .. } if requested_mode != "signatures" => {
return Some(PreDispatchResult {
overridden_mode: Some("signatures".to_string()),
reason: Some("excluded"),
pressure_downgraded: false,
budget_blocked: false,
budget_warning: None,
triage_filter_level: 0,
});
}
_ => {}
}
}
None
}
pub fn post_dispatch_record(
path: &str,
mode: &str,
original_tokens: usize,
sent_tokens: usize,
ledger: &mut ContextLedger,
overlay: &OverlayStore,
) -> PostDispatchResult {
post_dispatch_record_with_task(
path,
mode,
original_tokens,
sent_tokens,
ledger,
overlay,
None,
None,
)
}
pub fn post_dispatch_record_with_task(
path: &str,
mode: &str,
original_tokens: usize,
sent_tokens: usize,
ledger: &mut ContextLedger,
overlay: &OverlayStore,
task: Option<&str>,
project_root: Option<&str>,
) -> PostDispatchResult {
let prev_count = ledger.entries.len();
let prev_pressure = ledger.pressure().recommendation;
ledger.record_with_task(path, mode, original_tokens, sent_tokens, task);
let item_id = ContextItemId::from_file(path);
let state = overlay.apply_to_state(&item_id, ContextState::Included);
if state == ContextState::Excluded {
return PostDispatchResult {
eviction_hint: Some(format!("File '{path}' is excluded by overlay.")),
elicitation_hint: None,
resource_changed: true,
prefetch_hint: None,
};
}
let elicitation =
super::elicitation::check_elicitation_needed(ledger, Some(path), Some(sent_tokens))
.map(|s| s.format_fallback_hint());
let pressure = ledger.pressure();
let ignited = ledger.ignite_high_salience();
apply_reinjection_plan(ledger, &pressure.recommendation);
let new_entry = ledger.entries.len() != prev_count;
let pressure_shifted = pressure.recommendation != prev_pressure;
let resource_changed = new_entry || pressure_shifted || !ignited.is_empty();
if pressure.utilization > 0.9 {
let candidates = ledger.eviction_candidates_by_phi(3);
if !candidates.is_empty() {
let names: Vec<_> = candidates
.iter()
.take(3)
.map(|p| eviction_target_display(p, project_root))
.collect();
return PostDispatchResult {
eviction_hint: Some(format!(
"Context pressure {:.0}%. Evict: ctx_ledger(action=\"evict\", targets=\"{}\")",
pressure.utilization * 100.0,
names.join(", ")
)),
elicitation_hint: elicitation,
resource_changed,
prefetch_hint: None,
};
}
}
let prefetch_hint =
project_root.and_then(|root| crate::core::fep_prefetch::prefetch_hint(root, path, ledger));
{
if let (Some(task_str), Some(root)) = (task, project_root) {
let kernel =
crate::core::context_kernel::orchestrator::ContextKernel::for_project(root);
let ctx = crate::core::context_kernel::types::RetrievalContext {
query: task_str.to_owned(),
task: Some(task_str.to_owned()),
project_root: root.to_owned(),
budget: crate::core::context_field::TokenBudget {
total: original_tokens,
used: 0,
},
max_candidates: 10,
};
let plan = kernel.plan(&ctx);
let receipt = kernel.record_receipt(
&plan,
sent_tokens,
crate::core::context_kernel::types::ReceiptOutcome::Accepted,
);
let logger =
crate::core::context_kernel::shadow::ShadowLogger::default_for_project(root);
logger.log_receipt(&receipt);
}
}
PostDispatchResult {
eviction_hint: None,
elicitation_hint: elicitation,
resource_changed,
prefetch_hint,
}
}
fn eviction_target_display(path: &str, project_root: Option<&str>) -> String {
if let Some(root) = project_root.filter(|r| !r.is_empty()) {
let root_prefix = format!("{}/", root.trim_end_matches(['/', '\\']).replace('\\', "/"));
if let Some(rel) = path.strip_prefix(&root_prefix)
&& !rel.is_empty()
{
return rel.to_string();
}
}
path.to_string()
}
fn apply_reinjection_plan(ledger: &mut ContextLedger, action: &PressureAction) {
if *action != PressureAction::ForceCompression && *action != PressureAction::EvictLeastRelevant
{
return;
}
for entry in &mut ledger.entries {
if entry.state == Some(ContextState::Pinned) {
continue;
}
if entry.mode == "full" {
entry.mode = "map".to_string();
}
}
}
fn try_load_graph(project_root: &str) -> Option<crate::core::graph_provider::OpenGraphProvider> {
crate::core::graph_provider::open_best_effort(project_root)
}
pub fn triage_filter_level(profile: &crate::core::triage::profile::TaskProfileLocal) -> u8 {
if profile.confidence_milli < 300 {
0
} else if profile.context_need_milli < 300 {
2
} else {
u8::from(profile.context_need_milli < 600)
}
}
pub fn apply_triage_filter(
output: &str,
profile: &crate::core::triage::profile::TaskProfileLocal,
level: u8,
) -> (String, usize) {
if level == 0 || output.chars().count() < 500 {
return (output.to_string(), 0);
}
let trimmed = output.trim_start();
if (trimmed.starts_with('{') || trimmed.starts_with('['))
&& serde_json::from_str::<serde_json::Value>(trimmed).is_ok()
{
return (output.to_string(), 0);
}
let lines: Vec<&str> = output.lines().collect();
if let Some(json_start) = lines.iter().position(|l| {
let t = l.trim_start();
t.starts_with('{') || t.starts_with('[')
}) {
let json_portion = lines[json_start..].join("\n");
if serde_json::from_str::<serde_json::Value>(&json_portion).is_ok() {
return (output.to_string(), 0);
}
}
let filtered: Vec<&str> = match level {
1 => lines
.iter()
.copied()
.filter(|line| !is_boilerplate_line(line.trim_start()))
.collect(),
2 => {
let keywords = extract_task_keywords(&profile.task_class, &profile.intent);
lines
.iter()
.copied()
.filter(|line| {
let trimmed = line.trim();
is_structural_line(trimmed) || {
let lowercase = trimmed.to_lowercase();
keywords.iter().any(|keyword| lowercase.contains(keyword))
}
})
.collect()
}
_ => return (output.to_string(), 0),
};
let removed = lines.len().saturating_sub(filtered.len());
let mut result = filtered.join("\n");
result.push_str(&format!(
"\n[lean-ctx: {removed} lines filtered by triage (level {level})]"
));
(result, removed)
}
fn extract_task_keywords(task_class: &str, intent: &str) -> Vec<String> {
let mut keywords = task_class
.split(|character: char| !character.is_alphanumeric())
.chain(intent.split(|character: char| !character.is_alphanumeric()))
.filter(|keyword| !keyword.is_empty())
.map(str::to_lowercase)
.collect::<Vec<_>>();
keywords.sort_unstable();
keywords.dedup();
keywords
}
fn is_boilerplate_line(line: &str) -> bool {
line.starts_with("//")
&& !line.contains("TODO")
&& !line.contains("FIXME")
&& !line.contains("SAFETY")
}
fn is_structural_line(line: &str) -> bool {
line.contains('{')
|| line.contains('}')
|| line.starts_with("pub")
|| line.starts_with("fn")
|| line.starts_with("struct")
|| line.starts_with("impl")
|| line.starts_with("use")
|| line.starts_with("mod")
|| line.starts_with('#')
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::triage::profile::TaskProfileLocal;
#[test]
fn eviction_target_display_emits_resolvable_targets() {
assert_eq!(
eviction_target_display("/w/proj/src/a.rs", Some("/w/proj")),
"src/a.rs"
);
assert_eq!(
eviction_target_display("/other/b.rs", Some("/w/proj")),
"/other/b.rs"
);
assert_eq!(eviction_target_display("/x/c.rs", None), "/x/c.rs");
}
#[test]
fn pre_dispatch_passthrough_for_full() {
let result = pre_dispatch_read("src/main.rs", "full", None, None, None);
assert!(result.overridden_mode.is_none());
}
#[test]
fn pre_dispatch_passthrough_for_diff() {
let result = pre_dispatch_read("src/main.rs", "diff", None, None, None);
assert!(result.overridden_mode.is_none());
}
#[test]
fn pre_dispatch_passthrough_for_anchored_window() {
{
let mut bt = crate::core::bounce_tracker::global()
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
bt.set_seq(101);
bt.record_read("anchored-bouncy.yml", "map", 30, 400);
bt.set_seq(102);
bt.record_read("anchored-bouncy.yml", "full", 400, 400);
bt.set_seq(103);
bt.record_read("a2.yml", "map", 30, 400);
bt.set_seq(104);
bt.record_read("a2.yml", "full", 400, 400);
bt.set_seq(105);
bt.record_read("a3.yml", "map", 30, 400);
bt.set_seq(106);
bt.record_read("a3.yml", "full", 400, 400);
}
let result = pre_dispatch_read("anchored-new.yml", "anchored:10-40", None, None, None);
assert!(
result.overridden_mode.is_none(),
"anchored:N-M must not be overridden by bounce-prevention"
);
let bare = pre_dispatch_read("anchored-new.yml", "anchored", None, None, None);
assert!(
bare.overridden_mode.is_none(),
"bare anchored mode must not be overridden by bounce-prevention"
);
}
#[test]
fn pre_dispatch_passthrough_for_lines_multi_select() {
{
let mut bt = crate::core::bounce_tracker::global()
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
bt.set_seq(201);
bt.record_edit("multi-select-971.rs");
bt.set_seq(202);
}
let forced = pre_dispatch_read("multi-select-971.rs", "map", None, None, None);
assert_eq!(
forced.overridden_mode.as_deref(),
Some("full"),
"precondition: a recent edit must force a non-pinned mode to full"
);
let multi = pre_dispatch_read(
"multi-select-971.rs",
"lines:620-622,1214-1218",
None,
None,
None,
);
assert!(
multi.overridden_mode.is_none(),
"lines:A-B,C-D must not be overridden by bounce-prevention (#971)"
);
let single = pre_dispatch_read("multi-select-971.rs", "lines:620-622", None, None, None);
assert!(
single.overridden_mode.is_none(),
"lines:A-B must not be overridden by bounce-prevention"
);
}
#[test]
fn pre_dispatch_no_override_without_signals() {
let result = pre_dispatch_read("src/unknown.rs", "auto", None, None, None);
assert!(result.overridden_mode.is_none());
}
#[test]
fn pre_dispatch_bounce_prevention_forces_full() {
{
let mut bt = crate::core::bounce_tracker::global()
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
bt.set_seq(1);
bt.record_read("src/bouncy.yml", "map", 30, 400);
bt.set_seq(2);
bt.record_read("src/bouncy.yml", "full", 400, 400);
bt.set_seq(3);
bt.record_read("a2.yml", "map", 30, 400);
bt.set_seq(4);
bt.record_read("a2.yml", "full", 400, 400);
bt.set_seq(5);
bt.record_read("a3.yml", "map", 30, 400);
bt.set_seq(6);
bt.record_read("a3.yml", "full", 400, 400);
}
let result = pre_dispatch_read("new.yml", "auto", None, None, None);
assert_eq!(result.overridden_mode, Some("full".to_string()));
assert_eq!(result.reason, Some("bounce-prevention"));
}
#[test]
fn pressure_does_not_downgrade_explicit_full() {
let result = pre_dispatch_read(
"c.rs",
"full",
None,
None,
Some(&PressureAction::ForceCompression),
);
assert!(
result.overridden_mode.is_none(),
"explicit mode=full must never be downgraded by pressure"
);
assert!(!result.pressure_downgraded);
}
#[test]
fn pressure_does_not_downgrade_when_enforce_off() {
let result = pre_dispatch_read(
"c.rs",
"map",
None,
None,
Some(&PressureAction::EvictLeastRelevant),
);
assert!(
result.overridden_mode.is_none(),
"pressure must not downgrade when degradation.enforce is off"
);
assert!(!result.pressure_downgraded);
}
#[test]
fn no_pressure_downgrade_when_low() {
let result = pre_dispatch_read("c.rs", "full", None, None, Some(&PressureAction::NoAction));
assert!(result.overridden_mode.is_none());
assert!(!result.pressure_downgraded);
}
#[test]
fn suggest_compression_does_not_downgrade_when_enforce_off() {
let result = pre_dispatch_read(
"c.rs",
"auto",
None,
None,
Some(&PressureAction::SuggestCompression),
);
assert!(
result.overridden_mode.is_none(),
"suggest_compression must not downgrade when enforce is off"
);
assert!(!result.pressure_downgraded);
}
#[test]
fn suggest_compression_does_not_touch_explicit_full() {
let result = pre_dispatch_read(
"c.rs",
"full",
None,
None,
Some(&PressureAction::SuggestCompression),
);
assert!(result.overridden_mode.is_none());
assert!(!result.pressure_downgraded);
}
#[test]
fn post_dispatch_reinjection_downgrades_entries() {
let mut ledger = ContextLedger::with_window_size(1000);
ledger.record("a.rs", "full", 400, 400);
ledger.record("b.rs", "full", 400, 400);
let overlay = OverlayStore::new();
let result = post_dispatch_record("c.rs", "full", 300, 300, &mut ledger, &overlay);
assert!(result.resource_changed);
let a_entry = ledger.entries.iter().find(|e| e.path == "a.rs").unwrap();
assert_eq!(a_entry.mode, "map");
}
#[test]
fn ignited_item_resists_reinjection_downgrade() {
let mut ledger = ContextLedger::with_window_size(1000);
for i in 0..5 {
ledger.record(&format!("bg{i}.rs"), "full", 250, 250);
}
ledger.record("hot.rs", "full", 250, 250);
for e in &mut ledger.entries {
e.phi = Some(if e.path == "hot.rs" { 0.97 } else { 0.1 });
}
let ignited = ledger.ignite_high_salience();
assert_eq!(ignited, vec!["hot.rs".to_string()], "outlier should ignite");
apply_reinjection_plan(&mut ledger, &PressureAction::ForceCompression);
let hot = ledger.entries.iter().find(|e| e.path == "hot.rs").unwrap();
assert_eq!(hot.mode, "full", "ignited item keeps its full view");
let bg = ledger.entries.iter().find(|e| e.path == "bg0.rs").unwrap();
assert_eq!(bg.mode, "map", "non-ignited items are downgraded");
}
#[test]
fn overlay_pin_forces_full_mode() {
let dir = tempfile::tempdir().expect("tmp dir");
let root = dir.path();
let mut store = OverlayStore::new();
let target = ContextItemId::from_file("src/important.rs");
store.add(crate::core::context_overlay::ContextOverlay::new(
target,
OverlayOp::Pin { verbatim: false },
crate::core::context_overlay::OverlayScope::Project,
String::new(),
crate::core::context_overlay::OverlayAuthor::User,
));
store.save_project(root).unwrap();
let result = pre_dispatch_read(
"src/important.rs",
"auto",
None,
Some(root.to_str().unwrap()),
None,
);
assert_eq!(result.overridden_mode, Some("full".to_string()));
assert_eq!(result.reason, Some("pinned"));
}
#[test]
fn overlay_exclude_forces_signatures_mode() {
let dir = tempfile::tempdir().expect("tmp dir");
let root = dir.path();
let mut store = OverlayStore::new();
let target = ContextItemId::from_file("src/noisy.rs");
store.add(crate::core::context_overlay::ContextOverlay::new(
target,
OverlayOp::Exclude {
reason: "noise".to_string(),
},
crate::core::context_overlay::OverlayScope::Project,
String::new(),
crate::core::context_overlay::OverlayAuthor::User,
));
store.save_project(root).unwrap();
let result = pre_dispatch_read(
"src/noisy.rs",
"auto",
None,
Some(root.to_str().unwrap()),
None,
);
assert_eq!(result.overridden_mode, Some("signatures".to_string()));
assert_eq!(result.reason, Some("excluded"));
}
#[test]
fn pressure_downgrade_suggest_auto_to_map() {
let result = pressure_downgrade("auto", &PressureAction::SuggestCompression);
assert_eq!(result, Some("map".to_string()));
}
#[test]
fn pressure_downgrade_suggest_full_to_map() {
let result = pressure_downgrade("full", &PressureAction::SuggestCompression);
assert_eq!(result, Some("map".to_string()));
}
#[test]
fn pressure_downgrade_suggest_does_not_touch_signatures() {
let result = pressure_downgrade("signatures", &PressureAction::SuggestCompression);
assert!(result.is_none());
}
#[test]
fn pressure_downgrade_suggest_does_not_touch_diff() {
let result = pressure_downgrade("diff", &PressureAction::SuggestCompression);
assert!(result.is_none());
}
#[test]
fn pressure_downgrade_force_full_to_map() {
let result = pressure_downgrade("full", &PressureAction::ForceCompression);
assert_eq!(result, Some("map".to_string()));
}
#[test]
fn pressure_downgrade_force_auto_to_signatures() {
let result = pressure_downgrade("auto", &PressureAction::ForceCompression);
assert_eq!(result, Some("signatures".to_string()));
}
#[test]
fn pressure_downgrade_force_map_to_signatures() {
let result = pressure_downgrade("map", &PressureAction::ForceCompression);
assert_eq!(result, Some("signatures".to_string()));
}
#[test]
fn pressure_downgrade_force_does_not_touch_signatures() {
let result = pressure_downgrade("signatures", &PressureAction::ForceCompression);
assert!(result.is_none());
}
#[test]
fn pressure_downgrade_force_does_not_touch_lines() {
let result = pressure_downgrade("lines:1-50", &PressureAction::ForceCompression);
assert!(result.is_none());
}
#[test]
fn pressure_downgrade_evict_full_to_map() {
let result = pressure_downgrade("full", &PressureAction::EvictLeastRelevant);
assert_eq!(result, Some("map".to_string()));
}
#[test]
fn pressure_downgrade_evict_auto_to_signatures() {
let result = pressure_downgrade("auto", &PressureAction::EvictLeastRelevant);
assert_eq!(result, Some("signatures".to_string()));
}
#[test]
fn pressure_downgrade_evict_map_to_signatures() {
let result = pressure_downgrade("map", &PressureAction::EvictLeastRelevant);
assert_eq!(result, Some("signatures".to_string()));
}
#[test]
fn pressure_downgrade_noaction_returns_none() {
let result = pressure_downgrade("full", &PressureAction::NoAction);
assert!(result.is_none());
}
#[test]
fn pressure_downgrade_noaction_auto_returns_none() {
let result = pressure_downgrade("auto", &PressureAction::NoAction);
assert!(result.is_none());
}
#[test]
fn pre_dispatch_does_not_downgrade_full_under_force() {
if std::env::var("LCTX_NO_DEGRADE").is_ok() {
return;
}
let result = pre_dispatch_read(
"nd_test.rs",
"full",
None,
None,
Some(&PressureAction::ForceCompression),
);
assert!(result.overridden_mode.is_none());
assert!(!result.pressure_downgraded);
}
#[test]
fn pre_dispatch_does_not_downgrade_auto_when_enforce_off() {
if std::env::var("LCTX_NO_DEGRADE").is_ok() {
return;
}
let result = pre_dispatch_read(
"nd_test2.rs",
"auto",
None,
None,
Some(&PressureAction::EvictLeastRelevant),
);
assert!(result.overridden_mode.is_none());
assert!(!result.pressure_downgraded);
}
#[test]
fn estimate_tokens_diff_mode_is_small() {
let tokens = estimate_read_tokens("nonexistent.rs", "diff");
assert!(tokens < 500, "diff mode should estimate low: got {tokens}");
}
#[test]
fn estimate_tokens_signatures_smaller_than_full() {
let sig = estimate_read_tokens("nonexistent.rs", "signatures");
let full = estimate_read_tokens("nonexistent.rs", "full");
assert!(sig < full, "signatures={sig} should be < full={full}");
}
#[test]
fn estimate_tokens_lines_range() {
let tokens = estimate_read_tokens("nonexistent.rs", "lines:1-10");
assert!(tokens <= 200, "lines:1-10 should be small: got {tokens}");
}
#[test]
fn overlay_set_view_forces_specified_mode() {
let dir = tempfile::tempdir().expect("tmp dir");
let root = dir.path();
let mut store = OverlayStore::new();
let target = ContextItemId::from_file("src/big.rs");
store.add(crate::core::context_overlay::ContextOverlay::new(
target,
OverlayOp::SetView(crate::core::context_field::ViewKind::Map),
crate::core::context_overlay::OverlayScope::Project,
String::new(),
crate::core::context_overlay::OverlayAuthor::User,
));
store.save_project(root).unwrap();
let result = pre_dispatch_read(
"src/big.rs",
"auto",
None,
Some(root.to_str().unwrap()),
None,
);
assert_eq!(result.overridden_mode, Some("map".to_string()));
assert_eq!(result.reason, Some("overlay-set-view"));
}
use crate::core::triage::profile::TaskScopeLocal;
fn test_profile(confidence: u16, context_need: u16) -> TaskProfileLocal {
TaskProfileLocal {
task_class: "bug_fix".into(),
intent: "fix context gate filtering".into(),
complexity: "low".into(),
scope: TaskScopeLocal::SingleFile,
context_need_milli: context_need,
reasoning_need_milli: 0,
risk_signal_milli: 0,
confidence_milli: confidence,
}
}
#[test]
fn triage_filter_level_selects_expected_level() {
for (confidence, context_need, expected) in
[(200, 200, 0), (500, 200, 2), (500, 450, 1), (500, 700, 0)]
{
assert_eq!(
triage_filter_level(&test_profile(confidence, context_need)),
expected
);
}
}
#[test]
fn apply_triage_filter_level_zero_is_passthrough() {
let profile = test_profile(500, 200);
let output = "// boilerplate\n".repeat(40);
assert_eq!(apply_triage_filter(&output, &profile, 0), (output, 0));
}
#[test]
fn apply_triage_filter_short_output_is_passthrough() {
let profile = test_profile(500, 200);
let output = "fn main() {\n println!(\"hi\");\n}";
assert_eq!(apply_triage_filter(output, &profile, 2), (output.into(), 0));
}
#[test]
fn apply_triage_filter_level_one_preserves_actionable_comments() {
let profile = test_profile(500, 450);
let output = "// boilerplate comment\n".repeat(30)
+ "// TODO: keep this\n// FIXME: keep this\n// SAFETY: keep this\nfn keep_me() {}\n";
let (filtered, removed) = apply_triage_filter(&output, &profile, 1);
assert!(!filtered.contains("// boilerplate comment"));
assert!(filtered.contains("// TODO: keep this"));
assert!(filtered.contains("// FIXME: keep this"));
assert!(filtered.contains("// SAFETY: keep this"));
assert!(filtered.contains("[lean-ctx: 30 lines filtered by triage (level 1)]"));
assert_eq!(removed, 30);
}
#[test]
fn apply_triage_filter_level_two_keeps_keywords_and_structure() {
let profile = test_profile(500, 200);
let output = "// unrelated noise about widgets\n".repeat(20)
+ "fix the context gate\n"
+ "pub fn unrelated() {}\n"
+ "#[derive(Debug)]\n"
+ "mod inner {}\n";
let (filtered, removed) = apply_triage_filter(&output, &profile, 2);
assert!(filtered.contains("fix the context gate"));
assert!(filtered.contains("pub fn unrelated() {}"));
assert!(filtered.contains("#[derive(Debug)]"));
assert!(filtered.contains("mod inner {}"));
assert!(filtered.contains("[lean-ctx:"));
assert_eq!(removed, 20);
}
#[test]
fn benchmark_apply_triage_filter() {
use std::time::Instant;
let profile = test_profile(500, 200);
let output = "// unrelated noise about widgets\n".repeat(2_000);
let started = Instant::now();
for _ in 0..1_000 {
let (_, removed) = apply_triage_filter(&output, &profile, 2);
assert_eq!(removed, 2_000);
}
let average = started.elapsed() / 1_000;
println!("benchmark_apply_triage_filter: {average:?} per call");
}
#[test]
fn extract_task_keywords_normalizes_and_deduplicates() {
assert_eq!(
extract_task_keywords("bug_fix", "Fix context-gate"),
["bug", "context", "fix", "gate"]
);
}
}