use phago_agents::digester::Digester;
use phago_core::types::*;
use phago_runtime::colony::Colony;
use phago_core::topology::TopologyGraph;
#[test]
fn stale_edges_decay_while_active_edges_survive() {
let mut colony = Colony::new();
colony.ingest_document(
"Doc A",
"cell membrane protein transport channel receptor",
Position::new(0.0, 0.0),
);
colony.ingest_document(
"Doc B",
"cell membrane protein synthesis ribosome enzyme",
Position::new(0.0, 0.0),
);
colony.ingest_document(
"Doc C",
"cell membrane protein signaling pathway cascade",
Position::new(0.0, 0.0),
);
colony.ingest_document(
"Doc D (stale)",
"quantum entanglement superposition decoherence measurement",
Position::new(0.0, 0.0),
);
for _ in 0..3 {
colony.spawn(Box::new(Digester::new(Position::new(0.0, 0.0)).with_max_idle(200)));
}
colony.run(60);
let stats_baseline = colony.stats();
println!("--- Baseline (Tick {}) ---", stats_baseline.tick);
println!("Nodes: {}", stats_baseline.graph_nodes);
println!("Edges: {}", stats_baseline.graph_edges);
assert!(stats_baseline.graph_nodes > 0, "Should have nodes");
assert!(stats_baseline.graph_edges > 0, "Should have edges");
let graph = colony.substrate().graph();
let cell_nodes = graph.find_nodes_by_label("cell");
let membrane_nodes = graph.find_nodes_by_label("membrane");
let quantum_nodes = graph.find_nodes_by_label("quantum");
if !cell_nodes.is_empty() && !membrane_nodes.is_empty() {
if let Some(edge) = graph.get_edge(&cell_nodes[0], &membrane_nodes[0]) {
println!("cell-membrane edge: weight={:.3}, co_activations={}", edge.weight, edge.co_activations);
assert!(edge.co_activations >= 2, "Shared terms should have multiple co-activations");
}
}
if !quantum_nodes.is_empty() {
let q_neighbors = graph.neighbors(&quantum_nodes[0]);
if let Some((_, edge)) = q_neighbors.first() {
println!("quantum edge: weight={:.3}, co_activations={}", edge.weight, edge.co_activations);
}
}
colony.run(240);
let stats_after = colony.stats();
println!("--- After 240 more ticks (Tick {}) ---", stats_after.tick);
println!("Nodes: {}", stats_after.graph_nodes);
println!("Edges: {}", stats_after.graph_edges);
println!(
"Edge change: {} -> {} ({:.1}% reduction)",
stats_baseline.graph_edges,
stats_after.graph_edges,
(1.0 - stats_after.graph_edges as f64 / stats_baseline.graph_edges as f64) * 100.0
);
assert!(
stats_after.graph_edges <= stats_baseline.graph_edges,
"Edge count should not increase: before={}, after={}",
stats_baseline.graph_edges,
stats_after.graph_edges
);
}
#[test]
fn competitive_pruning_enforces_degree_cap() {
use phago_runtime::topology_impl::PetTopologyGraph;
let mut graph = PetTopologyGraph::new();
let hub_id = NodeId::new();
graph.add_node(NodeData {
id: hub_id,
label: "hub".to_string(),
node_type: NodeType::Concept,
position: Position::new(0.0, 0.0),
access_count: 1,
created_tick: 0,
embedding: None,
});
for i in 0..40 {
let spoke_id = NodeId::new();
graph.add_node(NodeData {
id: spoke_id,
label: format!("spoke_{}", i),
node_type: NodeType::Concept,
position: Position::new(0.0, 0.0),
access_count: 1,
created_tick: 0,
embedding: None,
});
graph.set_edge(hub_id, spoke_id, EdgeData {
weight: 0.1 + (i as f64) * 0.02, co_activations: 1,
created_tick: 0,
last_activated_tick: 0,
});
}
assert_eq!(graph.edge_count(), 40);
let pruned = graph.prune_to_max_degree(30);
println!("Pruned {} edges, remaining: {}", pruned.len(), graph.edge_count());
assert!(graph.edge_count() <= 30, "Should enforce degree cap: got {}", graph.edge_count());
let hub_neighbors = graph.neighbors(&hub_id);
for (_, edge) in &hub_neighbors {
assert!(edge.weight >= 0.3, "Weakest remaining edge should be >= 0.3, got {:.3}", edge.weight);
}
}