lean-ctx 3.9.18

Context Runtime for AI Agents with CCP. 71 MCP tools, 10 read modes, 95+ compression patterns, cross-session memory (CCP), persistent AI knowledge with temporal facts + contradiction detection, multi-agent context sharing, LITM-aware positioning, AAAK compact format, adaptive compression with Thompson Sampling bandits. Supports 24+ AI tools. Reduces LLM token consumption by up to 99%.
Documentation
use super::builtins::{builtin_exploration, builtin_profiles};
use super::*;

#[test]
fn builtin_profiles_count() {
    let builtins = builtin_profiles();
    assert_eq!(builtins.len(), 7);
    assert!(builtins.contains_key("coder"));
    assert!(builtins.contains_key("exploration"));
    assert!(builtins.contains_key("bugfix"));
    assert!(builtins.contains_key("hotfix"));
    assert!(builtins.contains_key("ci-debug"));
    assert!(builtins.contains_key("review"));
    assert!(builtins.contains_key("passthrough"));
}

#[test]
fn hotfix_has_minimal_budget() {
    let p = builtin_profiles().remove("hotfix").unwrap();
    assert_eq!(p.budget.max_context_tokens_effective(), 30_000);
    assert_eq!(p.budget.max_shell_invocations_effective(), 20);
    assert_eq!(p.read.default_mode_effective(), "signatures");
    assert_eq!(p.compression.output_density_effective(), "ultra");
}

#[test]
fn exploration_has_broad_context() {
    let p = builtin_profiles().remove("exploration").unwrap();
    assert_eq!(p.budget.max_context_tokens_effective(), 200_000);
    assert_eq!(p.read.default_mode_effective(), "map");
    assert!(p.read.prefer_cache_effective());
}

#[test]
fn profile_roundtrip_toml() {
    let original = builtin_exploration();
    let toml_str = format_as_toml(&original);
    let parsed: Profile = toml::from_str(&toml_str).unwrap();
    assert_eq!(parsed.profile.name, "exploration");
    assert_eq!(parsed.read.default_mode_effective(), "map");
    assert_eq!(parsed.budget.max_context_tokens_effective(), 200_000);
}

#[test]
fn merge_child_overrides_parent() {
    let parent = builtin_exploration();
    let child = Profile {
        profile: ProfileMeta {
            name: "custom".to_string(),
            inherits: Some("exploration".to_string()),
            description: String::new(),
        },
        read: ReadConfig {
            default_mode: Some("signatures".to_string()),
            ..ReadConfig::default()
        },
        compression: CompressionConfig::default(),
        translation: TranslationConfig::default(),
        layout: LayoutConfig::default(),
        memory: crate::core::memory_policy::MemoryPolicyOverrides::default(),
        verification: crate::core::output_verification::VerificationConfig::default(),
        budget: BudgetConfig {
            max_context_tokens: Some(10_000),
            ..BudgetConfig::default()
        },
        pipeline: PipelineConfig::default(),
        routing: RoutingConfig::default(),
        degradation: DegradationConfig::default(),
        autonomy: ProfileAutonomy::default(),
        output_hints: OutputHints::default(),
    };

    let merged = merge_profiles(parent, child);
    assert_eq!(merged.read.default_mode_effective(), "signatures");
    assert_eq!(merged.budget.max_context_tokens_effective(), 10_000);
    assert_eq!(
        merged.profile.description,
        "Broad context for understanding codebases"
    );
}

#[test]
fn merge_partial_child_inherits_parent_fields() {
    let parent = builtin_exploration();
    let child = Profile {
        profile: ProfileMeta {
            name: "partial".to_string(),
            inherits: Some("exploration".to_string()),
            description: String::new(),
        },
        read: ReadConfig {
            default_mode: Some("map".to_string()),
            ..ReadConfig::default()
        },
        compression: CompressionConfig::default(),
        translation: TranslationConfig::default(),
        layout: LayoutConfig::default(),
        memory: crate::core::memory_policy::MemoryPolicyOverrides::default(),
        verification: crate::core::output_verification::VerificationConfig::default(),
        budget: BudgetConfig::default(),
        pipeline: PipelineConfig::default(),
        routing: RoutingConfig::default(),
        degradation: DegradationConfig::default(),
        autonomy: ProfileAutonomy::default(),
        output_hints: OutputHints::default(),
    };

    let merged = merge_profiles(parent, child);
    assert_eq!(merged.read.default_mode_effective(), "map");
    assert_eq!(
        merged.read.max_tokens_per_file_effective(),
        80_000,
        "should inherit max_tokens_per_file from parent"
    );
    assert!(
        merged.read.prefer_cache_effective(),
        "should inherit prefer_cache from parent"
    );
    assert_eq!(
        merged.budget.max_context_tokens_effective(),
        200_000,
        "should inherit budget from parent"
    );
}

#[test]
fn load_builtin_by_name() {
    let p = load_profile("hotfix").unwrap();
    assert_eq!(p.profile.name, "hotfix");
    assert_eq!(p.read.default_mode_effective(), "signatures");
}

#[test]
fn load_nonexistent_returns_none() {
    assert!(load_profile("does-not-exist-xyz").is_none());
}

#[test]
fn list_profiles_includes_builtins() {
    let list = list_profiles();
    assert!(list.len() >= 5);
    let names: Vec<&str> = list.iter().map(|p| p.name.as_str()).collect();
    assert!(names.contains(&"exploration"));
    assert!(names.contains(&"hotfix"));
    assert!(names.contains(&"review"));
}

#[test]
fn active_profile_defaults_to_coder() {
    let _lock = crate::core::data_dir::test_env_lock();
    crate::test_env::remove_var("LEAN_CTX_PROFILE");
    let p = active_profile();
    assert_eq!(p.profile.name, "coder");
}

#[test]
fn active_profile_from_env() {
    let _lock = crate::core::data_dir::test_env_lock();
    crate::test_env::set_var("LEAN_CTX_PROFILE", "hotfix");
    let name = active_profile_name();
    assert_eq!(name, "hotfix");
    crate::test_env::remove_var("LEAN_CTX_PROFILE");
}

#[test]
fn profile_source_display() {
    assert_eq!(ProfileSource::Builtin.to_string(), "built-in");
    assert_eq!(ProfileSource::Global.to_string(), "global");
    assert_eq!(ProfileSource::Project.to_string(), "project");
}

#[test]
fn default_profile_has_sane_values() {
    let p = Profile {
        profile: ProfileMeta::default(),
        read: ReadConfig::default(),
        compression: CompressionConfig::default(),
        translation: TranslationConfig::default(),
        layout: LayoutConfig::default(),
        memory: crate::core::memory_policy::MemoryPolicyOverrides::default(),
        verification: crate::core::output_verification::VerificationConfig::default(),
        budget: BudgetConfig::default(),
        pipeline: PipelineConfig::default(),
        routing: RoutingConfig::default(),
        degradation: DegradationConfig::default(),
        autonomy: ProfileAutonomy::default(),
        output_hints: OutputHints::default(),
    };
    assert_eq!(p.read.default_mode_effective(), "auto");
    assert_eq!(p.compression.crp_mode_effective(), "tdd");
    assert_eq!(p.budget.max_context_tokens_effective(), 200_000);
    assert!(p.pipeline.compression_effective());
    assert!(p.pipeline.intent_effective());
}

#[test]
fn pipeline_layers_configurable() {
    let toml_str = r#"
[profile]
name = "no-intent"

[pipeline]
intent = false
relevance = false
"#;
    let p: Profile = toml::from_str(toml_str).unwrap();
    assert!(!p.pipeline.intent_effective());
    assert!(!p.pipeline.relevance_effective());
    assert!(p.pipeline.compression_effective());
    assert!(p.pipeline.translation_effective());
}

#[test]
fn partial_toml_fills_defaults() {
    let toml_str = r#"
[profile]
name = "minimal"

[read]
default_mode = "entropy"
"#;
    let p: Profile = toml::from_str(toml_str).unwrap();
    assert_eq!(p.read.default_mode_effective(), "entropy");
    assert_eq!(p.read.max_tokens_per_file_effective(), 50_000);
    assert_eq!(p.budget.max_context_tokens_effective(), 200_000);
    assert_eq!(p.compression.crp_mode_effective(), "tdd");
}

#[test]
fn partial_toml_leaves_unset_as_none() {
    let toml_str = r#"
[profile]
name = "sparse"

[read]
default_mode = "map"
"#;
    let p: Profile = toml::from_str(toml_str).unwrap();
    assert_eq!(p.read.default_mode, Some("map".to_string()));
    assert_eq!(p.read.max_tokens_per_file, None);
    assert_eq!(p.read.prefer_cache, None);
    assert_eq!(p.budget.max_context_tokens, None);
    assert_eq!(p.compression.crp_mode, None);
}