1#![allow(unused)]
2
3pub mod activation;
4pub mod antibody;
5pub mod builder;
6pub mod calibration;
7pub mod counterfactual;
8pub mod domain;
9#[cfg(feature = "embed")]
10pub mod embed;
11#[cfg(feature = "embed")]
12pub mod embed_cache;
13pub mod epidemic;
14pub mod error;
15pub mod flow;
16pub mod git_history;
17pub mod graph;
18pub mod layer;
19pub mod plasticity;
20pub mod query;
21pub mod refactor;
22pub mod resonance;
23pub mod runtime_overlay;
24pub mod seed;
25pub mod semantic;
26pub mod snapshot;
27pub mod snapshot_bin;
28pub mod taint;
29pub mod temporal;
30pub mod topology;
31pub mod tremor;
32pub mod trust;
33pub mod twins;
34pub mod types;
35pub mod xlr;
36
37#[cfg(test)]
38mod tests {
39 use crate::activation::*;
40 use crate::counterfactual::*;
41 use crate::error::*;
42 use crate::graph::*;
43 use crate::plasticity::*;
44 use crate::query::*;
45 use crate::resonance::*;
46 use crate::seed::*;
47 use crate::temporal::*;
48 use crate::topology::*;
49 use crate::types::*;
50 use crate::xlr::*;
51
52 #[test]
55 #[cfg(debug_assertions)]
56 #[should_panic(expected = "non-finite")]
57 fn finite_f32_rejects_nan() {
58 let _f = FiniteF32::new(f32::NAN);
60 }
61
62 #[test]
63 #[cfg(debug_assertions)]
64 #[should_panic(expected = "non-finite")]
65 fn finite_f32_rejects_inf() {
66 let _f = FiniteF32::new(f32::INFINITY);
68 }
69
70 #[test]
71 fn finite_f32_accepts_normal() {
72 let f = FiniteF32::new(1.0);
73 assert_eq!(f.get(), 1.0);
74 }
75
76 #[test]
77 fn finite_f32_total_order() {
78 let a = FiniteF32::new(0.5);
79 let b = FiniteF32::new(0.7);
80 assert!(a < b);
81 assert_eq!(a.cmp(&a), std::cmp::Ordering::Equal);
82 }
83
84 #[test]
85 fn pos_f32_rejects_zero() {
86 assert!(PosF32::new(0.0).is_none());
87 }
88
89 #[test]
90 fn pos_f32_rejects_negative() {
91 assert!(PosF32::new(-1.0).is_none());
92 }
93
94 #[test]
95 fn pos_f32_accepts_positive() {
96 assert!(PosF32::new(0.001).is_some());
97 }
98
99 #[test]
100 fn learning_rate_range() {
101 assert!(LearningRate::new(0.0).is_none());
102 assert!(LearningRate::new(1.1).is_none());
103 assert!(LearningRate::new(0.5).is_some());
104 assert!(LearningRate::new(1.0).is_some());
105 }
106
107 #[test]
108 fn decay_factor_range() {
109 assert!(DecayFactor::new(0.0).is_none());
110 assert!(DecayFactor::new(1.1).is_none());
111 assert!(DecayFactor::new(0.55).is_some());
112 }
113
114 #[test]
117 fn error_display_empty_graph() {
118 let e = M1ndError::EmptyGraph;
119 let msg = format!("{e}");
120 assert!(msg.contains("empty"), "Expected 'empty' in: {msg}");
121 }
122
123 #[test]
124 fn error_display_dangling_edge() {
125 let e = M1ndError::DanglingEdge {
126 edge: EdgeIdx::new(0),
127 node: NodeId::new(999),
128 };
129 let msg = format!("{e}");
130 assert!(msg.contains("dangling"));
131 }
132
133 fn build_test_graph() -> Graph {
136 let mut g = Graph::new();
137 g.add_node(
138 "mat_pe",
139 "Polietileno",
140 NodeType::Material,
141 &["plastico", "polimero"],
142 1000.0,
143 0.5,
144 )
145 .unwrap();
146 g.add_node(
147 "mat_pp",
148 "Polipropileno",
149 NodeType::Material,
150 &["plastico", "polimero"],
151 900.0,
152 0.3,
153 )
154 .unwrap();
155 g.add_node(
156 "mat_abs",
157 "ABS",
158 NodeType::Material,
159 &["plastico"],
160 800.0,
161 0.2,
162 )
163 .unwrap();
164 g.add_node(
165 "proc_inj",
166 "Injecao",
167 NodeType::Process,
168 &["processo"],
169 700.0,
170 0.4,
171 )
172 .unwrap();
173 g.add_node(
174 "proc_ext",
175 "Extrusao",
176 NodeType::Process,
177 &["processo"],
178 600.0,
179 0.1,
180 )
181 .unwrap();
182 g.add_node(
183 "prod_garrafa",
184 "Garrafa",
185 NodeType::Product,
186 &["produto"],
187 500.0,
188 0.6,
189 )
190 .unwrap();
191
192 g.add_edge(
193 NodeId::new(0),
194 NodeId::new(3),
195 "feeds_into",
196 FiniteF32::new(0.8),
197 EdgeDirection::Forward,
198 false,
199 FiniteF32::new(0.5),
200 )
201 .unwrap();
202 g.add_edge(
203 NodeId::new(1),
204 NodeId::new(3),
205 "feeds_into",
206 FiniteF32::new(0.7),
207 EdgeDirection::Forward,
208 false,
209 FiniteF32::new(0.3),
210 )
211 .unwrap();
212 g.add_edge(
213 NodeId::new(2),
214 NodeId::new(4),
215 "feeds_into",
216 FiniteF32::new(0.6),
217 EdgeDirection::Forward,
218 false,
219 FiniteF32::new(0.2),
220 )
221 .unwrap();
222 g.add_edge(
223 NodeId::new(3),
224 NodeId::new(5),
225 "produces",
226 FiniteF32::new(0.9),
227 EdgeDirection::Forward,
228 false,
229 FiniteF32::new(0.8),
230 )
231 .unwrap();
232 g.add_edge(
233 NodeId::new(0),
234 NodeId::new(1),
235 "similar_to",
236 FiniteF32::new(0.5),
237 EdgeDirection::Bidirectional,
238 false,
239 FiniteF32::ZERO,
240 )
241 .unwrap();
242
243 g.finalize().unwrap();
244 g
245 }
246
247 #[test]
248 fn graph_add_node_and_resolve() {
249 let mut g = Graph::new();
250 let n1 = g
251 .add_node("ext1", "Label1", NodeType::Module, &[], 0.0, 0.0)
252 .unwrap();
253 assert_eq!(n1, NodeId::new(0));
254 assert_eq!(g.num_nodes(), 1);
255 assert_eq!(g.resolve_id("ext1"), Some(NodeId::new(0)));
256 }
257
258 #[test]
259 fn graph_add_node_duplicate() {
260 let mut g = Graph::new();
261 g.add_node("ext1", "label1", NodeType::Module, &[], 0.0, 0.0)
262 .unwrap();
263 let n2 = g.add_node("ext1", "label2", NodeType::Module, &[], 0.0, 0.0);
264 assert!(matches!(n2, Err(M1ndError::DuplicateNode(_))));
265 }
266
267 #[test]
268 fn graph_add_edge_dangling() {
269 let mut g = Graph::new();
270 let n1 = g
271 .add_node("a", "A", NodeType::Module, &[], 0.0, 0.0)
272 .unwrap();
273 let bad = NodeId::new(999);
274 let e = g.add_edge(
275 n1,
276 bad,
277 "calls",
278 FiniteF32::ONE,
279 EdgeDirection::Forward,
280 false,
281 FiniteF32::ZERO,
282 );
283 assert!(matches!(e, Err(M1ndError::DanglingEdge { .. })));
284 }
285
286 #[test]
287 fn graph_finalize_builds_csr() {
288 let g = build_test_graph();
289 assert!(g.finalized);
290 assert_eq!(g.num_nodes(), 6);
291 assert!(g.num_edges() > 0);
292 assert!(g.pagerank_computed);
293 }
294
295 #[test]
296 fn graph_pagerank_computed() {
297 let g = build_test_graph();
298 let max_pr = (0..g.num_nodes() as usize)
299 .map(|i| g.nodes.pagerank[i].get())
300 .fold(0.0f32, f32::max);
301 assert!(max_pr > 0.0, "PageRank should have non-zero values");
302 }
303
304 #[test]
305 fn seed_finder_exact_match() {
306 let g = build_test_graph();
307 let seeds = SeedFinder::find_seeds(&g, "Polietileno", 200).unwrap();
308 assert!(!seeds.is_empty(), "Should find at least one seed");
309 assert_eq!(
310 seeds[0].1.get(),
311 1.0,
312 "Exact match should have relevance 1.0"
313 );
314 }
315
316 #[test]
317 fn seed_finder_tag_match() {
318 let g = build_test_graph();
319 let seeds = SeedFinder::find_seeds(&g, "plastico", 200).unwrap();
320 assert!(!seeds.is_empty(), "Should find seeds by tag");
321 }
322
323 #[test]
324 fn seed_finder_caps_at_max() {
325 let g = build_test_graph();
326 let seeds = SeedFinder::find_seeds(&g, "a", 2).unwrap();
327 assert!(seeds.len() <= 2);
328 }
329
330 #[test]
331 fn seed_finder_prefers_code_path_over_docs_for_same_label() {
332 let mut g = Graph::new();
333 let code = g
334 .add_node(
335 "code_resolve",
336 "resolve",
337 NodeType::Function,
338 &["m1nd"],
339 0.0,
340 0.0,
341 )
342 .unwrap();
343 let docs = g
344 .add_node(
345 "docs_resolve",
346 "resolve",
347 NodeType::File,
348 &["m1nd"],
349 0.0,
350 0.0,
351 )
352 .unwrap();
353
354 g.set_node_provenance(
355 code,
356 NodeProvenanceInput {
357 source_path: Some("~/m1nd/m1nd-core/src/seed.rs"),
358 line_start: Some(1),
359 line_end: Some(4),
360 excerpt: Some("fn resolve()"),
361 namespace: None,
362 canonical: true,
363 },
364 );
365 g.set_node_provenance(
366 docs,
367 NodeProvenanceInput {
368 source_path: Some("~/m1nd/docs/wiki/seed.md"),
369 line_start: Some(1),
370 line_end: Some(4),
371 excerpt: Some("resolve"),
372 namespace: None,
373 canonical: true,
374 },
375 );
376
377 g.finalize().unwrap();
378
379 let seeds = SeedFinder::find_seeds(&g, "resolve", 10).unwrap();
380 assert!(!seeds.is_empty());
381 assert_eq!(seeds[0].0, code, "code path should outrank docs path");
382 }
383
384 #[test]
385 fn seed_finder_prefers_multi_token_code_match_over_generic_single_token_hit() {
386 let mut g = Graph::new();
387 let precise = g
388 .add_node(
389 "file::m1nd-ingest/src/resolve.rs::struct::ResolutionStats",
390 "ResolutionStats",
391 NodeType::Struct,
392 &["rust", "m1nd"],
393 0.0,
394 0.0,
395 )
396 .unwrap();
397 let generic = g
398 .add_node(
399 "graph_concept",
400 "Graph",
401 NodeType::Concept,
402 &["graph"],
403 0.0,
404 0.0,
405 )
406 .unwrap();
407
408 g.set_node_provenance(
409 precise,
410 NodeProvenanceInput {
411 source_path: Some("~/m1nd/m1nd-ingest/src/resolve.rs"),
412 line_start: Some(1),
413 line_end: Some(4),
414 excerpt: Some("struct ResolutionStats"),
415 namespace: None,
416 canonical: true,
417 },
418 );
419 g.set_node_provenance(
420 generic,
421 NodeProvenanceInput {
422 source_path: Some("~/m1nd/docs/wiki/graph.md"),
423 line_start: Some(1),
424 line_end: Some(4),
425 excerpt: Some("Graph overview"),
426 namespace: None,
427 canonical: true,
428 },
429 );
430
431 g.finalize().unwrap();
432
433 let seeds =
434 SeedFinder::find_seeds(&g, "rust extractor impl ownership module resolution", 10)
435 .unwrap();
436 assert!(!seeds.is_empty());
437 assert_eq!(
438 seeds[0].0, precise,
439 "multi-token code symbol should outrank a generic concept hit"
440 );
441 }
442
443 #[test]
444 fn bloom_filter_basic() {
445 let mut bf = BloomFilter::with_capacity(1000, 0.01);
446 bf.insert(NodeId::new(42));
447 assert!(bf.probably_contains(NodeId::new(42)));
448 }
449
450 #[test]
451 fn wavefront_single_seed() {
452 let g = build_test_graph();
453 let engine = WavefrontEngine::new();
454 let config = PropagationConfig::default();
455 let seeds = vec![(NodeId::new(0), FiniteF32::ONE)];
456 let result = engine.propagate(&g, &seeds, &config).unwrap();
457 assert!(
458 !result.scores.is_empty(),
459 "Wavefront should activate at least one node"
460 );
461 assert!(result.scores[0].1.get() > 0.0);
462 }
463
464 #[test]
465 fn heap_single_seed() {
466 let g = build_test_graph();
467 let engine = HeapEngine::new();
468 let config = PropagationConfig::default();
469 let seeds = vec![(NodeId::new(0), FiniteF32::ONE)];
470 let result = engine.propagate(&g, &seeds, &config).unwrap();
471 assert!(
472 !result.scores.is_empty(),
473 "Heap should activate at least one node"
474 );
475 }
476
477 #[test]
478 fn hybrid_delegates_correctly() {
479 let g = build_test_graph();
480 let engine = HybridEngine::new();
481 let config = PropagationConfig::default();
482 let seeds = vec![(NodeId::new(0), FiniteF32::ONE)];
483 let result = engine.propagate(&g, &seeds, &config).unwrap();
484 assert!(!result.scores.is_empty());
485 }
486
487 #[test]
488 fn activation_empty_seeds_returns_empty() {
489 let g = build_test_graph();
490 let engine = WavefrontEngine::new();
491 let config = PropagationConfig::default();
492 let result = engine.propagate(&g, &[], &config).unwrap();
493 assert!(result.scores.is_empty());
494 }
495
496 #[test]
497 fn merge_dimensions_resonance_bonus() {
498 let make_dim = |dim: Dimension, scores: Vec<(NodeId, FiniteF32)>| DimensionResult {
499 scores,
500 dimension: dim,
501 elapsed_ns: 0,
502 };
503
504 let node = NodeId::new(0);
505 let score = FiniteF32::new(0.5);
506 let results = [
507 make_dim(Dimension::Structural, vec![(node, score)]),
508 make_dim(Dimension::Semantic, vec![(node, score)]),
509 make_dim(Dimension::Temporal, vec![(node, score)]),
510 make_dim(Dimension::Causal, vec![(node, score)]),
511 ];
512
513 let merged = merge_dimensions(&results, 10).unwrap();
514 assert!(!merged.activated.is_empty());
515 let activated = &merged.activated[0];
516 assert_eq!(activated.active_dimension_count, 4);
517 let base = 0.5 * 0.35 + 0.5 * 0.25 + 0.5 * 0.15 + 0.5 * 0.25;
518 let expected = base * RESONANCE_BONUS_4DIM;
519 assert!(
520 (activated.activation.get() - expected).abs() < 0.01,
521 "Expected ~{expected}, got {}",
522 activated.activation.get()
523 );
524 }
525
526 #[test]
527 fn xlr_sigmoid_gate() {
528 let zero = AdaptiveXlrEngine::sigmoid_gate(FiniteF32::ZERO);
529 assert!((zero.get() - 0.5).abs() < 0.01, "sigmoid(0) should be ~0.5");
530 let positive = AdaptiveXlrEngine::sigmoid_gate(FiniteF32::new(1.0));
531 assert!(positive.get() > 0.5, "sigmoid(+) should be > 0.5");
532 let negative = AdaptiveXlrEngine::sigmoid_gate(FiniteF32::new(-1.0));
533 assert!(negative.get() < 0.5, "sigmoid(-) should be < 0.5");
534 }
535
536 #[test]
537 fn xlr_pick_anti_seeds() {
538 let g = build_test_graph();
539 let xlr = AdaptiveXlrEngine::with_defaults();
540 let seeds = vec![NodeId::new(0)];
541 let anti = xlr.pick_anti_seeds(&g, &seeds).unwrap();
542 assert!(!anti.contains(&NodeId::new(0)));
543 }
544
545 #[test]
546 fn xlr_immunity_bfs() {
547 let g = build_test_graph();
548 let xlr = AdaptiveXlrEngine::with_defaults();
549 let seeds = vec![NodeId::new(0)];
550 let immunity = xlr.compute_immunity(&g, &seeds).unwrap();
551 assert!(immunity[0], "Seed itself should be immune");
552 }
553
554 #[test]
555 fn temporal_decay_clamps_negative_age() {
556 let scorer = TemporalDecayScorer::new(PosF32::new(168.0).unwrap());
557 let result = scorer.score_one(-10.0, FiniteF32::ZERO, None);
558 assert!(
559 (result.raw_decay.get() - 1.0).abs() < 0.01,
560 "Negative age should clamp to decay=1.0, got {}",
561 result.raw_decay.get()
562 );
563 }
564
565 #[test]
566 fn temporal_decay_exponential() {
567 let scorer = TemporalDecayScorer::new(PosF32::new(168.0).unwrap());
568 let result = scorer.score_one(168.0, FiniteF32::ZERO, None);
569 assert!(
570 (result.raw_decay.get() - 0.5).abs() < 0.05,
571 "After one half-life, decay ~0.5, got {}",
572 result.raw_decay.get()
573 );
574 }
575
576 #[test]
577 fn causal_chain_budget_limits() {
578 let g = build_test_graph();
579 let detector = CausalChainDetector::new(6, FiniteF32::new(0.01), 100);
580 let chains = detector.detect(&g, NodeId::new(0)).unwrap();
581 assert!(!chains.is_empty() || g.num_edges() == 0);
582 }
583
584 #[test]
585 fn louvain_detects_communities() {
586 let g = build_test_graph();
587 let detector = CommunityDetector::with_defaults();
588 let result = detector.detect(&g).unwrap();
589 assert!(result.num_communities >= 1);
590 assert_eq!(result.assignments.len(), g.num_nodes() as usize);
591 }
592
593 #[test]
594 fn louvain_empty_graph_error() {
595 let g = Graph::new();
596 let detector = CommunityDetector::with_defaults();
597 let result = detector.detect(&g);
598 assert!(matches!(result, Err(M1ndError::EmptyGraph)));
599 }
600
601 #[test]
602 fn bridge_detection() {
603 let g = build_test_graph();
604 let detector = CommunityDetector::with_defaults();
605 let communities = detector.detect(&g).unwrap();
606 let bridges = BridgeDetector::detect(&g, &communities).unwrap();
607 let _ = bridges;
608 }
609
610 #[test]
611 fn spectral_gap_empty_graph() {
612 let g = Graph::new();
613 let analyzer = SpectralGapAnalyzer::with_defaults();
614 let result = analyzer.analyze(&g);
615 assert!(matches!(result, Err(M1ndError::EmptyGraph)));
616 }
617
618 #[test]
619 fn wave_accumulator_complex_interference() {
620 let mut acc = WaveAccumulator::default();
621 let pulse1 = WavePulse {
622 node: NodeId::new(0),
623 amplitude: FiniteF32::ONE,
624 phase: FiniteF32::ZERO,
625 frequency: PosF32::new(1.0).unwrap(),
626 wavelength: PosF32::new(4.0).unwrap(),
627 hops: 0,
628 prev_node: NodeId::new(0),
629 };
630 acc.accumulate(&pulse1);
631 let amp = acc.amplitude().get();
632 assert!(
633 (amp - 1.0).abs() < 0.01,
634 "Single pulse amplitude should be ~1.0"
635 );
636 }
637
638 #[test]
639 fn standing_wave_propagation() {
640 let g = build_test_graph();
641 let propagator = StandingWavePropagator::new(5, FiniteF32::new(0.01), 10_000);
642 let seeds = vec![(NodeId::new(0), FiniteF32::ONE)];
643 let result = propagator
644 .propagate(
645 &g,
646 &seeds,
647 PosF32::new(1.0).unwrap(),
648 PosF32::new(4.0).unwrap(),
649 )
650 .unwrap();
651 assert!(result.pulses_processed > 0);
652 assert!(!result.antinodes.is_empty());
653 }
654
655 #[test]
656 fn query_memory_ring_buffer() {
657 let mut mem = QueryMemory::new(3, 10);
658 assert!(mem.is_empty());
659 for i in 0..5 {
660 mem.record(QueryRecord {
661 query_text: format!("query_{i}"),
662 seeds: vec![NodeId::new(i)],
663 activated_nodes: vec![NodeId::new(i), NodeId::new(i + 1)],
664 timestamp: i as f64,
665 });
666 }
667 assert_eq!(mem.len(), 3);
668 }
669
670 #[test]
671 fn plasticity_generation_check() {
672 let g = build_test_graph();
673 let engine = PlasticityEngine::new(&g, PlasticityConfig::default());
674 let _ = engine;
675 }
676
677 #[test]
678 fn removal_mask_basic() {
679 let g = build_test_graph();
680 let mut mask = RemovalMask::new(g.num_nodes(), g.num_edges());
681 assert!(!mask.is_node_removed(NodeId::new(0)));
682 mask.remove_node(&g, NodeId::new(0));
683 assert!(mask.is_node_removed(NodeId::new(0)));
684 mask.reset();
685 assert!(!mask.is_node_removed(NodeId::new(0)));
686 }
687}