use std::thread::sleep;
use std::time::Duration;
use noos::{Decision, LLMEvent, Regulator};
const WINDOW_MS: u64 = 500;
const QUICK_WAIT_MS: u64 = 20;
const PAST_WINDOW_WAIT_MS: u64 = 600;
fn main() {
println!("╔════════════════════════════════════════════════════════════════╗");
println!("║ Demo 5 — Implicit correction (Session 32) ║");
println!("╚════════════════════════════════════════════════════════════════╝\n");
println!(
"Regulator window: {} ms\nAll three scenarios use the same `Regulator::for_user('alice')\n.with_implicit_correction_window(500ms)` builder.\n",
WINDOW_MS
);
scenario_1_fast_retries_build_pattern();
scenario_2_window_expiry_fails_closed();
scenario_3_different_cluster_fails_closed();
println!("\n── Takeaway ───────────────────────────────────────────────────");
println!("Implicit correction detection is the adoption unlock for");
println!("procedural memory: apps don't have to wire explicit");
println!("`LLMEvent::UserCorrection` events — the regulator detects retries");
println!("structurally from timing + topic continuity, then feeds the");
println!("correction store which drives ProceduralWarning pre-generation.");
println!("Compared to content-memory stores (Mem0, Letta, Zep) which");
println!("require semantic search at retrieval time, the pattern fires");
println!("BEFORE generation — the app can use `inject_corrections` to");
println!("prepend learned examples to the next LLM prompt.");
}
fn scenario_1_fast_retries_build_pattern() {
println!("── Scenario 1 — three fast same-cluster retries ───────────────");
let mut r = Regulator::for_user("alice")
.with_implicit_correction_window(Duration::from_millis(WINDOW_MS));
println!(" turn 1: 'Refactor fetch_user to be async'");
r.on_event(LLMEvent::TurnStart {
user_message: "Refactor fetch_user to be async".into(),
});
r.on_event(LLMEvent::TurnComplete {
full_response: "(unsatisfactory response 1)".into(),
});
sleep(Duration::from_millis(QUICK_WAIT_MS));
println!(" turn 2: 'Fix the fetch_user async refactoring' [+20ms]");
r.on_event(LLMEvent::TurnStart {
user_message: "Fix the fetch_user async refactoring".into(),
});
println!(
" → implicit_corrections_count = {}",
r.implicit_corrections_count()
);
r.on_event(LLMEvent::TurnComplete {
full_response: "(unsatisfactory response 2)".into(),
});
sleep(Duration::from_millis(QUICK_WAIT_MS));
println!(" turn 3: 'Make fetch_user async properly' [+20ms]");
r.on_event(LLMEvent::TurnStart {
user_message: "Make fetch_user async properly".into(),
});
println!(
" → implicit_corrections_count = {}",
r.implicit_corrections_count()
);
r.on_event(LLMEvent::TurnComplete {
full_response: "(unsatisfactory response 3)".into(),
});
sleep(Duration::from_millis(QUICK_WAIT_MS));
println!(" turn 4: 'Update fetch_user to async version' [+20ms]");
r.on_event(LLMEvent::TurnStart {
user_message: "Update fetch_user to async version".into(),
});
println!(
" → implicit_corrections_count = {}",
r.implicit_corrections_count()
);
match r.decide() {
Decision::ProceduralWarning { patterns } => {
println!(" → decide() = ProceduralWarning");
for p in &patterns {
println!(
" pattern: {} (learned_from_turns={}, confidence={:.2})",
p.pattern_name, p.learned_from_turns, p.confidence
);
for (i, ex) in p.example_corrections.iter().enumerate() {
println!(" example[{}]: {:?}", i, ex);
}
}
}
other => println!(" → decide() = {other:?} [unexpected — pattern should have fired]"),
}
println!();
}
fn scenario_2_window_expiry_fails_closed() {
println!("── Scenario 2 — retry outside the window ──────────────────────");
let mut r = Regulator::for_user("bob")
.with_implicit_correction_window(Duration::from_millis(WINDOW_MS));
println!(" turn 1: 'Refactor fetch_user to be async'");
r.on_event(LLMEvent::TurnStart {
user_message: "Refactor fetch_user to be async".into(),
});
r.on_event(LLMEvent::TurnComplete {
full_response: "resp".into(),
});
println!(" waiting {PAST_WINDOW_WAIT_MS}ms (past the {WINDOW_MS}ms window)...");
sleep(Duration::from_millis(PAST_WINDOW_WAIT_MS));
println!(" turn 2: 'Fix the fetch_user async refactoring' [too late]");
r.on_event(LLMEvent::TurnStart {
user_message: "Fix the fetch_user async refactoring".into(),
});
println!(
" → implicit_corrections_count = {} (temporal gate failed closed)",
r.implicit_corrections_count()
);
println!();
}
fn scenario_3_different_cluster_fails_closed() {
println!("── Scenario 3 — fast retry, different topic cluster ───────────");
let mut r = Regulator::for_user("carol")
.with_implicit_correction_window(Duration::from_millis(WINDOW_MS));
println!(" turn 1: 'Refactor fetch_user to be async' [cluster: async+fetch_user]");
r.on_event(LLMEvent::TurnStart {
user_message: "Refactor fetch_user to be async".into(),
});
r.on_event(LLMEvent::TurnComplete {
full_response: "resp".into(),
});
sleep(Duration::from_millis(QUICK_WAIT_MS));
println!(
" turn 2: 'Explain tokio channels and scheduling' [cluster: channels+explain]"
);
r.on_event(LLMEvent::TurnStart {
user_message: "Explain tokio channels and scheduling".into(),
});
println!(
" → implicit_corrections_count = {} (topic gate failed closed)",
r.implicit_corrections_count()
);
println!();
}