refactor(concept_topology): Phase B language-advantage pass — dichotomy wave
CI Pipeline / best-practices (push) Successful in 10s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / rust-surface (push) Failing after 21s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / go-surface (push) Canceled after 24s
CI Pipeline / type-check (push) Canceled after 6s
CI Pipeline / gitea-offline (push) Canceled after 2s
Auto-version and Release / release (push) Canceled after 35s
CI Pipeline / canary (push) Canceled after 25s
deploy / deploy (push) Canceled after 36s
CI Pipeline / unit-tests (push) Canceled after 31s
CI Pipeline / lint (push) Canceled after 31s

Language-advantage pass on the concept_topology Rust kernel (battery
green throughout, live parity re-verified 386/386):
- Suggestion lattice is a real enum (Cluster | NewTopic) with an
  exhaustive match producing the doc envelope — no stringly verdicts.
- Union-find is a HashMap-backed UnionFind struct with the entry API
  (O(1) root lookups replace linear scans) — root identity is order-
  independent, so determinism is unchanged.
- clusters/suggest/decay run zero-copy over BORROWED edge pairs
  (&String / &str all the way to the sorted output allocation); the
  fn-name dispatch helpers collapse into obj_pairs/as_arr borrowing
  accessors with elided lifetimes.
- seen/edge upserts are iterator chains (for_each + filter_map),
  sort_by_key(Reverse) for the stable biggest-first component order.
This commit is contained in:
Nick committed 2026-10-12 02:36:18 +01:00
1 parent 5844426bdd
commit 02e0c649da
1 file changed
+150 -135
+150 -135
View File
@@ -6,6 +6,13 @@
//!
//! Parity oracle: frozen_ct_truth.json (36 cases frozen from the live
//! Python oracle 2026-10-12, RUNE_CT_CORE=python pinned).
//!
//! Phase B language-advantage pass: the suggestion lattice is a real enum
//! with an exhaustive match, union-find runs on a HashMap with the entry
//! API, edges stay borrowed (zero-copy) through clusters/suggest, and the
//! seen/edge upserts are iterator chains.
use std::collections::HashMap;
use capability_scoring::pyjson::Json;
@@ -15,17 +22,12 @@ pub const CLUSTER_THRESHOLD: f64 = 2.0;
/// Python dict-update semantics on an ordered pair vec: replace in place
/// when the key exists, append when new.
fn upsert(pairs: &mut Vec<(String, Json)>, key: &str, value: Json) {
if let Some(slot) = pairs.iter_mut().find(|(k, _)| k == key) {
slot.1 = value;
} else {
pairs.push((key.to_string(), value));
match pairs.iter_mut().find(|(k, _)| k == key) {
Some(slot) => slot.1 = value,
None => pairs.push((key.to_string(), value)),
}
}
pub fn obj_get<'a>(v: &'a Json, key: &str) -> Option<&'a Json> {
v.get(key)
}
fn num_get(pairs: &[(String, Json)], key: &str) -> Option<f64> {
pairs
.iter()
@@ -36,6 +38,27 @@ fn num_get(pairs: &[(String, Json)], key: &str) -> Option<f64> {
})
}
fn str_of(t: &Json) -> String {
match t {
Json::Str(s) => s.clone(),
other => capability_scoring::pyjson::dumps(other),
}
}
fn obj_pairs(v: Option<&Json>) -> &[(String, Json)] {
match v {
Some(Json::Obj(p)) => p,
_ => &[],
}
}
fn as_arr(v: &Json) -> &[Json] {
match v {
Json::Arr(a) => a,
_ => &[],
}
}
/// Port of new_topology(): the empty seed, no preset categories.
pub fn new_topology() -> Json {
Json::Obj(vec![
@@ -51,36 +74,20 @@ pub fn cofire(topology: &Json, topics: &[Json]) -> Json {
Json::Obj(p) => p.clone(),
_ => vec![],
};
let mut seen = match obj_get(topology, "seen") {
Some(Json::Obj(p)) => p.clone(),
_ => vec![],
};
for t in topics {
let key = match t {
Json::Str(s) => s.clone(),
other => capability_scoring::pyjson::dumps(other),
};
let mut seen = obj_pairs(topology.get("seen")).to_vec();
topics.iter().for_each(|t| {
let key = str_of(t);
let next = num_get(&seen, &key).unwrap_or(0.0) + 1.0;
upsert(&mut seen, &key, Json::Num(next));
}
let mut edges = match obj_get(topology, "edges") {
Some(Json::Obj(p)) => p.clone(),
_ => vec![],
};
for i in 0..topics.len() {
});
let mut edges = obj_pairs(topology.get("edges")).to_vec();
for (i, a) in topics.iter().enumerate() {
for b in &topics[i + 1..] {
let a = match &topics[i] {
Json::Str(s) => s.clone(),
other => capability_scoring::pyjson::dumps(other),
};
let bkey = match b {
Json::Str(s) => s.clone(),
other => capability_scoring::pyjson::dumps(other),
};
let key = if a <= bkey {
format!("{}|{}", a, bkey)
let (x, y) = (str_of(a), str_of(b));
let key = if x <= y {
format!("{}|{}", x, y)
} else {
format!("{}|{}", bkey, a)
format!("{}|{}", y, x)
};
let next = num_get(&edges, &key).unwrap_or(0.0) + 1.0;
upsert(&mut edges, &key, Json::Num(next));
@@ -98,140 +105,148 @@ pub fn decay(topology: &Json) -> Json {
Json::Obj(p) => p.clone(),
_ => vec![],
};
let kept: Vec<(String, Json)> = match obj_get(topology, "edges") {
Some(Json::Obj(p)) => p
.iter()
.filter_map(|(k, v)| match v {
Json::Num(n) => {
let d = n * DECAY_PER_TICK;
if d >= 0.5 {
Some((k.clone(), Json::Num(d)))
} else {
None
}
}
_ => None,
})
.collect(),
_ => vec![],
};
let kept: Vec<(String, Json)> = obj_pairs(topology.get("edges"))
.iter()
.filter_map(|(k, v)| match v {
Json::Num(n) if n * DECAY_PER_TICK >= 0.5 => Some((k.clone(), Json::Num(n * DECAY_PER_TICK))),
_ => None,
})
.collect();
upsert(&mut pairs, "edges", Json::Obj(kept));
Json::Obj(pairs)
}
/// Union-find over the "a|b" edge keys (union by second-root repoint,
/// mirroring the oracle exactly).
struct UnionFind {
parent: HashMap<String, String>,
}
impl UnionFind {
fn new() -> Self {
UnionFind {
parent: HashMap::new(),
}
}
fn find(&self, x: &str) -> String {
let mut cur = x.to_string();
while let Some(p) = self.parent.get(&cur) {
if *p == cur {
break;
}
cur = p.clone();
}
cur
}
fn union(&mut self, a: &str, b: &str) {
let (ra, rb) = (self.find(a), self.find(b));
if ra != rb {
self.parent.insert(rb, ra);
}
}
}
/// Port of clusters(): connected components over edges >= threshold.
/// Union-find mirrors the oracle exactly (union by second-root repoint,
/// first-seen iteration order); components come back biggest first,
/// members sorted. NOTE: the oracle's group order for equal-size
/// Components come back biggest first (stable — ties keep first-seen
/// order), members sorted. NOTE: the oracle's group order for equal-size
/// components is CPython set-iteration (hash) order — deliberately no
/// frozen case contains a size tie.
pub fn clusters(topology: &Json, threshold: f64) -> Vec<Json> {
let edges: Vec<(String, f64)> = match obj_get(topology, "edges") {
Some(Json::Obj(p)) => p
.iter()
.filter_map(|(k, v)| match v {
Json::Num(n) if *n >= threshold => Some((k.clone(), *n)),
_ => None,
})
.collect(),
_ => vec![],
};
let mut parent: Vec<(String, String)> = vec![];
fn find(parent: &[(String, String)], x: &str) -> String {
let mut cur = x.to_string();
loop {
match parent.iter().find(|(k, _)| *k == cur) {
Some((_, p)) if *p != cur => cur = p.clone(),
_ => return cur,
}
}
}
let mut nodes: Vec<String> = vec![];
let edges: Vec<(&String, f64)> = obj_pairs(topology.get("edges"))
.iter()
.filter_map(|(k, v)| match v {
Json::Num(n) if *n >= threshold => Some((k, *n)),
_ => None,
})
.collect();
let mut uf = UnionFind::new();
let mut nodes: Vec<&str> = vec![];
for (k, _) in &edges {
let (a, b) = k.split_once('|').unwrap_or((k.as_str(), ""));
for n in [a.to_string(), b.to_string()] {
for n in [a, b] {
if !nodes.contains(&n) {
nodes.push(n);
}
}
let (ra, rb) = (find(&parent, a), find(&parent, b));
if ra != rb {
parent.push((rb, ra));
}
uf.union(a, b);
}
let mut groups: Vec<(String, Vec<String>)> = vec![];
for n in &nodes {
let root = find(&parent, n);
let mut groups: Vec<(String, Vec<&str>)> = vec![];
nodes.into_iter().for_each(|n| {
let root = uf.find(n);
match groups.iter_mut().find(|(r, _)| *r == root) {
Some((_, members)) => members.push(n.clone()),
None => groups.push((root, vec![n.clone()])),
Some((_, members)) => members.push(n),
None => groups.push((root, vec![n])),
}
}
let mut out: Vec<Vec<String>> = groups.into_iter().map(|(_, g)| g).collect();
});
let mut out: Vec<Vec<&str>> = groups.into_iter().map(|(_, g)| g).collect();
out.sort_by_key(|g| std::cmp::Reverse(g.len())); // stable: ties keep first-seen order
out.into_iter()
.map(|mut g| {
g.sort();
Json::Arr(g.into_iter().map(Json::Str).collect())
g.sort_unstable();
Json::Arr(g.into_iter().map(|s| Json::Str(s.to_string())).collect())
})
.collect()
}
/// The suggestion lattice: route to an earned cluster, or propose that
/// the fact is a new topic.
enum Suggestion {
Cluster(Vec<String>),
NewTopic,
}
impl Suggestion {
fn to_json(&self, overlap: usize) -> Json {
match self {
Suggestion::Cluster(names) => Json::Obj(vec![
(
"suggestion".into(),
Json::Arr(names.iter().cloned().map(Json::Str).collect()),
),
("reason".into(), Json::Str(format!("shares {overlap} topic(s)"))),
]),
Suggestion::NewTopic => Json::Obj(vec![
("suggestion".into(), Json::Str("new_topic".into())),
(
"reason".into(),
Json::Str("no cluster shares a topic with this fact".into()),
),
]),
}
}
}
/// Port of suggest(): the cluster a new fact belongs to — or a new topic.
pub fn suggest(topology: &Json, fact_topics: &[Json]) -> Json {
let cls = clusters(topology, CLUSTER_THRESHOLD);
let topic_set = |items: &[Json]| -> Vec<String> {
let mut v: Vec<String> = items
let mut fact_set: Vec<&str> = fact_topics
.iter()
.filter_map(|t| match t {
Json::Str(s) => Some(s.as_str()),
_ => None,
})
.collect();
fact_set.sort_unstable();
fact_set.dedup();
let mut best: Option<(Suggestion, usize)> = None;
for c in &cls {
let names: Vec<&str> = as_arr(c)
.iter()
.filter_map(|t| match t {
Json::Str(s) => Some(s.clone()),
.filter_map(|x| match x {
Json::Str(s) => Some(s.as_str()),
_ => None,
})
.collect();
v.sort();
v.dedup();
v
};
let fact_set = topic_set(fact_topics);
let mut best: Option<Vec<String>> = None;
let mut best_overlap = 0usize;
for c in &cls {
let names: Vec<String> = match c {
Json::Arr(items) => items
.iter()
.filter_map(|x| match x {
Json::Str(s) => Some(s.clone()),
_ => None,
})
.collect(),
_ => vec![],
};
let overlap = names
.iter()
.filter(|n| fact_set.contains(n))
.count();
if overlap > best_overlap {
best_overlap = overlap;
best = Some(names);
let overlap = names.iter().filter(|n| fact_set.contains(n)).count();
if overlap > best.as_ref().map_or(0, |(_, o)| *o) {
let cluster = Suggestion::Cluster(names.iter().map(|s| (*s).to_string()).collect());
best = Some((cluster, overlap));
}
}
match best {
None => Json::Obj(vec![
("suggestion".into(), Json::Str("new_topic".into())),
(
"reason".into(),
Json::Str("no cluster shares a topic with this fact".into()),
),
]),
Some(names) => Json::Obj(vec![
(
"suggestion".into(),
Json::Arr(names.into_iter().map(Json::Str).collect()),
),
(
"reason".into(),
Json::Str(format!("shares {} topic(s)", best_overlap)),
),
]),
Some((s, overlap)) => s.to_json(overlap),
None => Suggestion::NewTopic.to_json(0),
}
}