refactor(memory_selector): Phase B language-advantage pass — dichotomy wave

Unify the four self-scored decision kernels' shared floor/tag/cap loop
into one generic floored_rows iterator consumer — neurons/graphs/
abstraction/consolidated each keep ONLY their scoring (and the neuron
trigger-scan prefilter), dropping four hand-rolled copies of the same
below-floor-drop, tag, budget-cap shape. Behavior unchanged — battery
9/9, clippy --all-targets -D warnings 0, live parity 536/536 against
the frozen oracle.
This commit is contained in:
Nick committed 2026-10-13 18:31:51 +01:00
1 parent 6bdd28521a
commit f2ff903e65
1 file changed
+59 -70
+59 -70
View File
@@ -157,6 +157,35 @@ pub fn select_core(candidates: &[Value], budget: i64, min_score: f64, types: &[S
})
}
/// Shared per-source row loop (Phase B): the floor/tag/cap shape every
/// self-scored decision kernel shares — below-floor rows drop, survivors
/// are tagged {text, score, kind, source}, the cap stops the scan. Callers
/// own only the scoring (and any prefilter, e.g. the neuron trigger scan).
fn floored_rows(
pairs: impl Iterator<Item = (String, f64)>,
kind: &str,
source: &str,
budget: i64,
min_score: f64,
) -> Vec<Value> {
let mut out: Vec<Value> = Vec::new();
for (text, score) in pairs {
if score < min_score {
continue;
}
out.push(json!({
"text": text,
"score": score,
"kind": kind,
"source": source,
}));
if out.len() >= budget.max(0) as usize {
break;
}
}
out
}
/// _neurons_recall's post-IO decision math: trigger scan (a neuron that does
/// not match the task is not injected merely because it is important), lexical
/// scoring, the ONE floor, budget cap.
@@ -169,8 +198,7 @@ pub fn neurons_decision(neurons: &[Value], query: &str, budget: i64, min_score:
.to_string()
})
.collect();
let mut out: Vec<Value> = Vec::new();
for neuron in neurons {
let pairs = neurons.iter().filter_map(|neuron| {
let triggers = match neuron.get("triggers") {
Some(Value::Array(t)) => t.clone(),
_ => Vec::new(),
@@ -180,30 +208,21 @@ pub fn neurons_decision(neurons: &[Value], query: &str, budget: i64, min_score:
.map(|s| task_words.contains(&s.to_string()))
.unwrap_or(false)
}) {
continue;
return None;
}
let text = py_str(neuron.get("text"));
let score = lex_overlap_score(&text, query);
if score < min_score {
continue;
}
let slug = py_str(neuron.get("slug"));
let slug = if slug.is_empty() {
"warm".to_string()
} else {
slug
};
out.push(json!({
"text": format!("[{slug}] {text}"),
"score": score,
"kind": "neuron",
"source": "warm_neuron_store.list_neurons",
}));
if out.len() >= budget.max(0) as usize {
break;
}
}
Value::Array(out)
let slug = if slug.is_empty() { "warm".to_string() } else { slug };
Some((format!("[{slug}] {text}"), score))
});
Value::Array(floored_rows(
pairs,
"neuron",
"warm_neuron_store.list_neurons",
budget,
min_score,
))
}
/// _graphs_recall's post-IO decision math: lexical score with the
@@ -215,50 +234,26 @@ pub fn graphs_decision(
budget: i64,
min_score: f64,
) -> Value {
let mut out: Vec<Value> = Vec::new();
for tv in texts {
let pairs = texts.iter().map(|tv| {
let text = py_str(Some(tv));
let mut score = lex_overlap_score(&text, query);
if score == 0.0 {
score = 1.0 / std::cmp::max(n_task_words, 1) as f64;
}
if score < min_score {
continue;
}
out.push(json!({
"text": text,
"score": score,
"kind": "graph",
"source": "graph_memory.query",
}));
if out.len() >= budget.max(0) as usize {
break;
}
}
Value::Array(out)
(text, score)
});
Value::Array(floored_rows(pairs, "graph", "graph_memory.query", budget, min_score))
}
/// _abstraction_recall's post-IO decision math: LIKE matches are only
/// candidates — each must clear the floor.
pub fn abstraction_decision(whats: &[Value], query: &str, budget: i64, min_score: f64) -> Value {
let mut out: Vec<Value> = Vec::new();
for wv in whats {
let pairs = whats.iter().map(|wv| {
let text = py_str(Some(wv));
let score = lex_overlap_score(&text, query);
if score < min_score {
continue;
}
out.push(json!({
"text": text,
"score": score,
"kind": "abstraction",
"source": "abstraction facts",
}));
if out.len() >= budget.max(0) as usize {
break;
}
}
Value::Array(out)
(text, score)
});
Value::Array(floored_rows(pairs, "abstraction", "abstraction facts", budget, min_score))
}
/// _consolidated_recall's post-IO decision math: knowledge competes under the
@@ -269,24 +264,18 @@ pub fn consolidated_decision(
budget: i64,
min_score: f64,
) -> Value {
let mut out: Vec<Value> = Vec::new();
for cv in contents {
let pairs = contents.iter().map(|cv| {
let text = py_str(Some(cv));
let score = lex_overlap_score(&text, query);
if score < min_score {
continue;
}
out.push(json!({
"text": text,
"score": score,
"kind": "consolidated",
"source": "memory_consolidation",
}));
if out.len() >= budget.max(0) as usize {
break;
}
}
Value::Array(out)
(text, score)
});
Value::Array(floored_rows(
pairs,
"consolidated",
"memory_consolidation",
budget,
min_score,
))
}
/// _persona_recall's pre-IO gate: only self/personality types run the persona