Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 3 additions & 250 deletions apps/daemon/src/intelligence/classifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,254 +234,7 @@ pub fn classify_task(message: &str, ctx: &SessionContext) -> TaskClassification

// ─── Tests ────────────────────────────────────────────────────────────────────

// Tests live in classifier/tests.rs. Moved out when the suite grew to target
// the mutation gate's 32 surviving mutants, all of which are in classify_task.
#[cfg(test)]
mod tests {
use super::*;

fn ctx(message_count: usize, prior_failure: bool) -> SessionContext {
SessionContext {
message_count,
prior_model: None,
prior_failure,
}
}

#[test]
fn simple_short_message() {
let r = classify_task("rename this variable", &ctx(0, false));
assert_eq!(r.complexity, TaskComplexity::Simple);
}

#[test]
fn empty_message_does_not_panic() {
let r = classify_task("", &ctx(0, false));
// Empty message has no word count > 20 so should be Simple or Moderate
assert!(matches!(
r.complexity,
TaskComplexity::Simple | TaskComplexity::Moderate
));
}

#[test]
fn unicode_only_does_not_panic() {
let r = classify_task("مرحبا بالعالم 🦀", &ctx(0, false));
let _ = r.complexity; // just verify no panic
}

#[test]
fn very_long_message_does_not_panic() {
let long = "word ".repeat(30_000);
let r = classify_task(&long, &ctx(0, false));
// Very long = Complex or DeepReasoning
assert!(matches!(
r.complexity,
TaskComplexity::Complex | TaskComplexity::DeepReasoning | TaskComplexity::Moderate
));
}

#[test]
fn prior_failure_forces_deep_reasoning() {
let r = classify_task("what is 2+2", &ctx(0, true));
assert_eq!(r.complexity, TaskComplexity::DeepReasoning);
assert_eq!(r.confidence, 1.0);
assert!(r.prior_failure);
}

#[test]
fn deep_keyword_routes_to_deep_reasoning() {
let r = classify_task(
"architect from scratch a completely new event sourcing system",
&ctx(0, false),
);
assert_eq!(r.complexity, TaskComplexity::DeepReasoning);
}

#[test]
fn security_audit_is_complex() {
let r = classify_task(
"perform a security audit of the authentication system across all files",
&ctx(0, false),
);
assert!(matches!(
r.complexity,
TaskComplexity::Complex | TaskComplexity::DeepReasoning
));
}

#[test]
fn moderate_keyword_is_moderate() {
let r = classify_task(
"write a function that parses JSON and returns a struct",
&ctx(0, false),
);
assert!(matches!(
r.complexity,
TaskComplexity::Moderate | TaskComplexity::Complex
));
}

#[test]
fn high_message_depth_increases_complexity() {
let r_shallow = classify_task("fix this bug", &ctx(2, false));
let r_deep = classify_task("fix this bug", &ctx(25, false));
// Deep history should increase complexity score
let score_shallow = match r_shallow.complexity {
TaskComplexity::Simple => 0,
TaskComplexity::Moderate => 1,
TaskComplexity::Complex => 2,
TaskComplexity::DeepReasoning => 3,
};
let score_deep = match r_deep.complexity {
TaskComplexity::Simple => 0,
TaskComplexity::Moderate => 1,
TaskComplexity::Complex => 2,
TaskComplexity::DeepReasoning => 3,
};
assert!(score_deep >= score_shallow);
}

#[test]
fn confidence_is_in_range() {
for msg in [
"rename x",
"implement a full auth system",
"architect from scratch",
"",
] {
let r = classify_task(msg, &ctx(0, false));
assert!(
r.confidence >= 0.0 && r.confidence <= 1.0,
"confidence out of range: {}",
r.confidence
);
}
}

// ── Additional coverage for 20+ test functions (MI.T24) ──────────────────

#[test]
fn rename_variable_is_simple() {
let r = classify_task("rename the variable `count` to `total`", &ctx(0, false));
assert_eq!(r.complexity, TaskComplexity::Simple);
}

#[test]
fn fix_typo_is_simple() {
let r = classify_task("fix typo in the README", &ctx(0, false));
assert_eq!(r.complexity, TaskComplexity::Simple);
}

#[test]
fn what_is_question_is_simple_or_moderate() {
let r = classify_task(
"what is the difference between Vec and slice in Rust?",
&ctx(0, false),
);
assert!(matches!(
r.complexity,
TaskComplexity::Simple | TaskComplexity::Moderate
));
}

#[test]
fn implement_function_is_moderate_or_complex() {
let r = classify_task(
"implement a function that parses an ISO 8601 date string and returns a chrono DateTime",
&ctx(0, false),
);
assert!(matches!(
r.complexity,
TaskComplexity::Moderate | TaskComplexity::Complex
));
}

#[test]
fn refactor_is_at_least_moderate() {
let r = classify_task(
"refactor the session handler to use the new error type",
&ctx(0, false),
);
let level = match r.complexity {
TaskComplexity::Simple => 0,
TaskComplexity::Moderate => 1,
TaskComplexity::Complex => 2,
TaskComplexity::DeepReasoning => 3,
};
assert!(
level >= 1,
"refactor should be at least Moderate, got {level}"
);
}

#[test]
fn unit_test_keyword_is_at_least_moderate() {
let r = classify_task("write a unit test for the cost estimator", &ctx(0, false));
assert!(matches!(
r.complexity,
TaskComplexity::Moderate | TaskComplexity::Complex
));
}

#[test]
fn authentication_across_codebase_is_complex_or_deep() {
let r = classify_task(
"implement authentication and authorization across the entire codebase",
&ctx(0, false),
);
assert!(matches!(
r.complexity,
TaskComplexity::Complex | TaskComplexity::DeepReasoning
));
}

#[test]
fn multi_file_keyword_with_context_is_at_least_moderate() {
// "multi-file" fires the complex keyword (+4). A longer message avoids
// the short-message penalty (-2 for <20 words).
let r = classify_task(
"update the multi-file session handling and context management to properly \
support cancellation tokens and propagate errors across all file boundaries",
&ctx(0, false),
);
assert!(matches!(
r.complexity,
TaskComplexity::Moderate | TaskComplexity::Complex | TaskComplexity::DeepReasoning
));
}

#[test]
fn whitespace_only_does_not_panic() {
let r = classify_task(" \t\n ", &ctx(0, false));
let _ = r.complexity; // just verify no panic
}

#[test]
fn code_block_only_does_not_panic() {
let r = classify_task(
"```\nfn main() { println!(\"hello\"); }\n```",
&ctx(0, false),
);
let _ = r.complexity; // verify no panic; code block signal should fire
}

#[test]
fn novel_design_is_deep_reasoning() {
let r = classify_task(
"design a novel event sourcing architecture from scratch for our audit log system",
&ctx(0, false),
);
assert_eq!(r.complexity, TaskComplexity::DeepReasoning);
}

#[test]
fn signals_list_is_populated_for_complex_task() {
let r = classify_task(
"perform a comprehensive security audit of the authentication module across all files",
&ctx(0, false),
);
assert!(
!r.signals.is_empty(),
"signals list should be populated for a complex task"
);
}
}
mod tests;
Loading