use super::enforce::{KernelMode, enforce_plan, resolve_mode};
use super::orchestrator::ContextKernel;
use super::policy::ContextPolicy;
use super::types::{ContextPlanV1, ContextReceiptV1, PlanEntry, ReceiptOutcome, RetrievalContext};
#[derive(Debug, Clone)]
pub(crate) struct KernelVerdict {
pub supplement: Option<String>,
pub suppress: Vec<String>,
pub budget_used: usize,
}
#[derive(Debug, Clone)]
pub(crate) struct KernelEnrichment {
pub plan: ContextPlanV1,
pub blocks: String,
pub verdict: KernelVerdict,
pub enforced_mode: KernelMode,
}
pub(crate) fn kernel_gate(_path: &str, _project_root: &str) -> bool {
false
}
pub(crate) fn kernel_enrich(
task: &str,
project_root: &str,
budget_tokens: usize,
) -> Option<KernelEnrichment> {
let capped_budget = budget_tokens.min(150);
let kernel = ContextKernel::for_project(project_root);
let ctx = RetrievalContext {
query: task.to_owned(),
task: Some(task.to_owned()),
project_root: project_root.to_owned(),
budget: crate::core::context_field::TokenBudget {
total: capped_budget,
used: 0,
},
max_candidates: 20,
};
let mode = resolve_mode(project_root);
let plan = enforce_plan_for_mode(kernel.plan(&ctx), &ContextPolicy::default(), mode);
let enrichments: Vec<&PlanEntry> = plan
.selected
.iter()
.filter(|entry| entry.provider != "context.ledger")
.collect();
let blocks = format_enrichment_blocks(&enrichments);
enrichment_from_plan(plan, blocks, capped_budget, mode)
}
fn enforce_plan_for_mode(
plan: ContextPlanV1,
policy: &ContextPolicy,
mode: KernelMode,
) -> ContextPlanV1 {
if mode != KernelMode::Enforce {
return plan;
}
let result = enforce_plan(&plan, policy, mode);
if !result.blocked.is_empty() {
tracing::debug!(
blocked = result.blocked.len(),
"kernel enforce: plan entries blocked by policy"
);
}
ContextPlanV1 {
selected: result.allowed,
..plan
}
}
fn enrichment_from_plan(
plan: ContextPlanV1,
blocks: String,
budget: usize,
enforced_mode: KernelMode,
) -> Option<KernelEnrichment> {
let verdict = verdict_from_blocks(blocks, budget);
let blocks = verdict.supplement.clone()?;
Some(KernelEnrichment {
plan,
blocks,
verdict,
enforced_mode,
})
}
fn verdict_from_blocks(blocks: String, budget: usize) -> KernelVerdict {
let blocks = truncate_to_token_budget(blocks, budget);
let supplement = (!blocks.is_empty()).then(|| blocks.clone());
let budget_used = supplement
.as_deref()
.map_or(0, crate::core::tokens::count_tokens);
KernelVerdict {
supplement,
suppress: Vec::new(),
budget_used,
}
}
fn truncate_to_token_budget(mut text: String, budget: usize) -> String {
if crate::core::tokens::count_tokens(&text) <= budget {
return text;
}
let mut low = 0;
let mut high = text.len();
while low < high {
let middle = low + (high - low).div_ceil(2);
let boundary = text.floor_char_boundary(middle);
if crate::core::tokens::count_tokens(&text[..boundary]) <= budget {
low = middle;
} else {
high = middle - 1;
}
}
text.truncate(text.floor_char_boundary(low));
text
}
fn format_enrichment_blocks(entries: &[&PlanEntry]) -> String {
let mut out = String::new();
append_provider_block(&mut out, entries, "knowledge.facts", "Relevant Knowledge");
append_provider_block(&mut out, entries, "memory.episodic", "Relevant Episodes");
append_provider_block(
&mut out,
entries,
"memory.procedural",
"Relevant Procedures",
);
append_provider_block(&mut out, entries, "session.state", "Relevant Session State");
out
}
fn append_provider_block(
output: &mut String,
entries: &[&PlanEntry],
provider: &str,
heading: &str,
) {
let mut found = false;
for entry in entries
.iter()
.copied()
.filter(|entry| entry.provider == provider)
.filter(|entry| !entry.reason.trim().is_empty())
.filter(|entry| entry.reason != "selected by compiler")
{
if !found {
output.push_str("\n## ");
output.push_str(heading);
output.push('\n');
found = true;
}
output.push_str("- ");
output.push_str(&entry.reason);
output.push_str(" (phi=");
output.push_str(&format!("{:.2}", entry.phi));
output.push_str(")\n");
}
}
pub(crate) fn emit_plan_event(plan: &ContextPlanV1) {
use crate::core::ocla_bus::{self, OclaEvent};
ocla_bus::emit(OclaEvent::AgentChainEvent {
agent_id: format!("kernel:{}", plan.plan_id),
action: format!(
"plan_created:selected={},excluded={},budget={}/{}",
plan.selected.len(),
plan.excluded.len(),
plan.budget.used_tokens,
plan.budget.total_tokens,
),
parent_agent: None,
});
}
pub(crate) fn emit_receipt_event(receipt: &ContextReceiptV1) {
use crate::core::ocla_bus::{self, OclaEvent};
ocla_bus::emit(OclaEvent::AgentChainEvent {
agent_id: format!("kernel:{}", receipt.receipt_id),
action: format!(
"receipt_recorded:tokens={},outcome={:?}",
receipt.delivered_tokens, receipt.outcome,
),
parent_agent: Some(receipt.plan_id.clone()),
});
}
pub(crate) fn apply_feedback(receipt: &ContextReceiptV1) {
use crate::core::context_field::{FieldWeights, set_active_weights};
let arm_name = match receipt.outcome {
ReceiptOutcome::Accepted => "balanced",
ReceiptOutcome::Rejected => "aggressive",
ReceiptOutcome::Partial => "conservative",
ReceiptOutcome::Unknown => return,
};
let mut bandit = crate::core::bandit::ThresholdBandit::default();
bandit.update(arm_name, receipt.outcome == ReceiptOutcome::Accepted);
let best_idx = bandit.best_arm_idx_by_mean();
if let Some(best_arm) = bandit.arms.get(best_idx) {
set_active_weights(FieldWeights::from_arm(best_arm));
}
}
pub(crate) fn format_plan_summary(plan: &ContextPlanV1) -> String {
let mut out = String::new();
let plan_prefix = &plan.plan_id[..plan.plan_id.len().min(8)];
out.push_str(&format!(
"[kernel] plan={plan_prefix} intent=\"{}\" budget={}/{}\n",
plan.intent, plan.budget.used_tokens, plan.budget.total_tokens,
));
out.push_str(&format!(
" selected={} excluded={} deferred={}\n",
plan.selected.len(),
plan.excluded.len(),
plan.deferred.len(),
));
let mut providers: Vec<_> = plan.provider_stats.iter().collect();
providers.sort_unstable_by_key(|(k, _)| *k);
for (provider, stat) in providers {
out.push_str(&format!(
" {provider}: {}/{} candidates, {} tokens\n",
stat.candidates_selected, stat.candidates_offered, stat.tokens_used,
));
}
out
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use super::super::enforce::KernelMode;
use super::super::policy::ContextPolicy;
use super::super::types::PlanBudget;
use super::{
ContextPlanV1, PlanEntry, enforce_plan_for_mode, enrichment_from_plan,
format_enrichment_blocks, kernel_gate, verdict_from_blocks,
};
fn plan(selected: Vec<PlanEntry>) -> ContextPlanV1 {
ContextPlanV1 {
plan_id: "plan".to_owned(),
intent: "test".to_owned(),
budget: PlanBudget {
total_tokens: 150,
used_tokens: 0,
remaining_tokens: 150,
},
selected,
excluded: Vec::new(),
deferred: Vec::new(),
provider_stats: HashMap::new(),
}
}
fn entry(reason: &str) -> PlanEntry {
PlanEntry {
object_id: "fact".to_owned(),
provider: "knowledge.facts".to_owned(),
view: "summary".to_owned(),
tokens: 1,
phi: 0.8,
reason: reason.to_owned(),
}
}
#[test]
fn budget_capped_at_150() {
let item = entry(&"token ".repeat(1_000));
let blocks = format_enrichment_blocks(&[&item]);
let enrichment = enrichment_from_plan(plan(vec![item]), blocks, 150, KernelMode::Shadow)
.expect("long enrichment should be truncated, not removed");
assert!(enrichment.verdict.budget_used <= 150);
}
#[test]
fn empty_supplement_when_no_candidates() {
let verdict = verdict_from_blocks(String::new(), 150);
assert!(verdict.supplement.is_none());
assert_eq!(verdict.budget_used, 0);
}
#[test]
fn compiler_selection_placeholders_are_omitted() {
let placeholder = entry("selected by compiler");
assert!(format_enrichment_blocks(&[&placeholder]).is_empty());
}
#[test]
fn verdict_has_correct_budget_used() {
let item = entry("Known constraint");
let blocks = format_enrichment_blocks(&[&item]);
let enrichment = enrichment_from_plan(plan(vec![item]), blocks, 150, KernelMode::Shadow)
.expect("entry should produce enrichment");
assert_eq!(
enrichment.verdict.budget_used,
crate::core::tokens::count_tokens(enrichment.verdict.supplement.as_deref().unwrap())
);
}
#[test]
fn kernel_gate_returns_false_by_default() {
assert!(!kernel_gate("src/lib.rs", "/project"));
}
#[test]
fn backward_compat_enrichment_still_works() {
let item = entry("Known constraint");
let blocks = format_enrichment_blocks(&[&item]);
let enrichment = enrichment_from_plan(plan(vec![item]), blocks, 150, KernelMode::Shadow)
.expect("entry should produce enrichment");
assert_eq!(enrichment.blocks, enrichment.verdict.supplement.unwrap());
assert_eq!(enrichment.enforced_mode, KernelMode::Shadow);
}
#[test]
fn test_enforce_mode_blocks_policy_violations() {
let mut blocked = entry("blocked");
blocked.provider = "excluded.provider".to_owned();
let policy = ContextPolicy {
blocked_sources: vec![blocked.provider.clone()],
..ContextPolicy::default()
};
let enforced = enforce_plan_for_mode(
plan(vec![entry("allowed"), blocked]),
&policy,
KernelMode::Enforce,
);
assert_eq!(enforced.selected.len(), 1);
assert_eq!(enforced.selected[0].reason, "allowed");
}
#[test]
fn test_shadow_mode_allows_all_entries() {
let mut blocked = entry("blocked");
blocked.provider = "excluded.provider".to_owned();
let policy = ContextPolicy {
blocked_sources: vec![blocked.provider.clone()],
..ContextPolicy::default()
};
let shadow = enforce_plan_for_mode(
plan(vec![entry("allowed"), blocked]),
&policy,
KernelMode::Shadow,
);
assert_eq!(shadow.selected.len(), 2);
}
}