hub differentiation + refine_target for automatic section targeting
Pattern separation for memory graph: when a file-level node (e.g. identity.md) has section children, redistribute its links to the best-matching section using cosine similarity. - differentiate_hub: analyze hub, propose link redistribution - refine_target: at link creation time, automatically target the most specific section instead of the file-level hub - Applied refine_target in all four link creation paths (digest links, journal enrichment, apply consolidation, link-add command) - Saturated hubs listed in agent topology header with "DO NOT LINK" This prevents hub formation proactively (refine_target) and remediates existing hubs (differentiate command). Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
This commit is contained in:
parent
3afc947b88
commit
4530837057
3 changed files with 334 additions and 7 deletions
69
src/main.rs
69
src/main.rs
|
|
@ -92,6 +92,7 @@ fn main() {
|
|||
"digest-links" => cmd_digest_links(&args[2..]),
|
||||
"journal-enrich" => cmd_journal_enrich(&args[2..]),
|
||||
"apply-consolidation" => cmd_apply_consolidation(&args[2..]),
|
||||
"differentiate" => cmd_differentiate(&args[2..]),
|
||||
"trace" => cmd_trace(&args[2..]),
|
||||
"list-keys" => cmd_list_keys(),
|
||||
"list-edges" => cmd_list_edges(),
|
||||
|
|
@ -154,6 +155,8 @@ Commands:
|
|||
Enrich journal entry with conversation links
|
||||
apply-consolidation [--apply] [--report FILE]
|
||||
Extract and apply actions from consolidation reports
|
||||
differentiate [KEY] [--apply]
|
||||
Redistribute hub links to section-level children
|
||||
trace KEY Walk temporal links: semantic ↔ episodic ↔ conversation
|
||||
list-keys List all node keys (one per line)
|
||||
list-edges List all edges (tsv: source target strength type)
|
||||
|
|
@ -438,6 +441,11 @@ fn cmd_link_add(args: &[String]) -> Result<(), String> {
|
|||
let target = store.resolve_key(&args[1])?;
|
||||
let reason = if args.len() > 2 { args[2..].join(" ") } else { String::new() };
|
||||
|
||||
// Refine target to best-matching section
|
||||
let source_content = store.nodes.get(&source)
|
||||
.map(|n| n.content.as_str()).unwrap_or("");
|
||||
let target = neuro::refine_target(&store, source_content, &target);
|
||||
|
||||
// Find UUIDs
|
||||
let source_uuid = store.nodes.get(&source)
|
||||
.map(|n| n.uuid)
|
||||
|
|
@ -714,6 +722,67 @@ fn cmd_apply_consolidation(args: &[String]) -> Result<(), String> {
|
|||
digest::apply_consolidation(&mut store, do_apply, report_file)
|
||||
}
|
||||
|
||||
fn cmd_differentiate(args: &[String]) -> Result<(), String> {
|
||||
let do_apply = args.iter().any(|a| a == "--apply");
|
||||
let key_arg: Option<&str> = args.iter()
|
||||
.find(|a| !a.starts_with("--"))
|
||||
.map(|s| s.as_str());
|
||||
|
||||
let mut store = capnp_store::Store::load()?;
|
||||
|
||||
if let Some(key) = key_arg {
|
||||
// Differentiate a specific hub
|
||||
let resolved = store.resolve_key(key)?;
|
||||
let moves = neuro::differentiate_hub(&store, &resolved)
|
||||
.ok_or_else(|| format!("'{}' is not a file-level hub with sections", resolved))?;
|
||||
|
||||
// Group by target section for display
|
||||
let mut by_section: std::collections::BTreeMap<String, Vec<&neuro::LinkMove>> =
|
||||
std::collections::BTreeMap::new();
|
||||
for mv in &moves {
|
||||
by_section.entry(mv.to_section.clone()).or_default().push(mv);
|
||||
}
|
||||
|
||||
println!("Hub '{}' — {} links to redistribute across {} sections\n",
|
||||
resolved, moves.len(), by_section.len());
|
||||
|
||||
for (section, section_moves) in &by_section {
|
||||
println!(" {} ({} links):", section, section_moves.len());
|
||||
for mv in section_moves.iter().take(5) {
|
||||
println!(" [{:.3}] {} — {}", mv.similarity,
|
||||
mv.neighbor_key, mv.neighbor_snippet);
|
||||
}
|
||||
if section_moves.len() > 5 {
|
||||
println!(" ... and {} more", section_moves.len() - 5);
|
||||
}
|
||||
}
|
||||
|
||||
if !do_apply {
|
||||
println!("\nTo apply: poc-memory differentiate {} --apply", resolved);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let (applied, skipped) = neuro::apply_differentiation(&mut store, &moves);
|
||||
store.save()?;
|
||||
println!("\nApplied: {} Skipped: {}", applied, skipped);
|
||||
} else {
|
||||
// Show all differentiable hubs
|
||||
let hubs = neuro::find_differentiable_hubs(&store);
|
||||
if hubs.is_empty() {
|
||||
println!("No file-level hubs with sections found above threshold");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("Differentiable hubs (file-level nodes with sections):\n");
|
||||
for (key, degree, sections) in &hubs {
|
||||
println!(" {:40} deg={:3} sections={}", key, degree, sections);
|
||||
}
|
||||
println!("\nRun: poc-memory differentiate KEY to preview a specific hub");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cmd_trace(args: &[String]) -> Result<(), String> {
|
||||
if args.is_empty() {
|
||||
return Err("Usage: poc-memory trace KEY".into());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue