graph: community isolation scoring + sort:isolation query

Add community_isolation() to Graph — computes per-community ratio of
internal vs total edge weight. 1.0 = fully isolated, 0.0 = all edges
external.

New query: sort:isolation — sorts nodes by their community's isolation
score, most isolated first. Useful for aiming organize agents at
poorly-integrated knowledge clusters.

New CLI: poc-memory graph communities [N] [--min-size M] — lists
communities sorted by isolation with member preview. Reveals islands
like the Shannon theory cluster (3 nodes, 100% isolated, 0 cross-edges)
and large agent-journal clusters (20-30 nodes, 95% isolated).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kent Overstreet 2026-03-20 12:55:14 -04:00
parent d0f126b709
commit e6613f97bb
4 changed files with 141 additions and 0 deletions

View file

@ -656,3 +656,40 @@ pub fn cmd_interference(threshold: f32) -> Result<(), String> {
Ok(())
}
/// Show communities sorted by isolation (most isolated first).
/// Useful for finding poorly-integrated knowledge clusters that need
/// organize agents aimed at them.
pub fn cmd_communities(top_n: usize, min_size: usize) -> Result<(), String> {
let store = store::Store::load()?;
let g = store.build_graph();
let infos = g.community_info();
let total = infos.len();
let shown: Vec<_> = infos.into_iter()
.filter(|c| c.size >= min_size)
.take(top_n)
.collect();
println!("{} communities total ({} with size >= {})\n",
total, shown.len(), min_size);
println!("{:<6} {:>5} {:>7} {:>7} members", "id", "size", "iso", "cross");
println!("{}", "-".repeat(70));
for c in &shown {
let preview: Vec<&str> = c.members.iter()
.take(5)
.map(|s| s.as_str())
.collect();
let more = if c.size > 5 {
format!(" +{}", c.size - 5)
} else {
String::new()
};
println!("{:<6} {:>5} {:>6.0}% {:>7} {}{}",
c.id, c.size, c.isolation * 100.0, c.cross_edges,
preview.join(", "), more);
}
Ok(())
}