1use crate::connectome_manager::ConnectomeManager;
22use crate::models::{CorticalArea, CorticalID};
23use crate::types::{BduError, BduResult};
24use feagi_evolutionary::RuntimeGenome;
25use feagi_npu_neural::types::{Precision, QuantizationSpec};
26use parking_lot::RwLock;
27use std::sync::Arc;
28use tracing::{debug, error, info, trace, warn};
29
30fn autogen_subregion_display_name(genome_title: &str) -> String {
34 let t = genome_title.trim();
35 if t.is_empty() || t.eq_ignore_ascii_case("untitled") {
36 "Autogen Circuit".to_string()
37 } else {
38 t.to_string()
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum DevelopmentStage {
45 Initialization,
47 Corticogenesis,
49 Voxelogenesis,
51 Neurogenesis,
53 Synaptogenesis,
55 Completed,
57 Failed,
59}
60
61#[derive(Debug, Clone)]
63pub struct DevelopmentProgress {
64 pub stage: DevelopmentStage,
66 pub progress: u8,
68 pub cortical_areas_created: usize,
70 pub neurons_created: usize,
72 pub synapses_created: usize,
74 pub duration_ms: u64,
76}
77
78impl Default for DevelopmentProgress {
79 fn default() -> Self {
80 Self {
81 stage: DevelopmentStage::Initialization,
82 progress: 0,
83 cortical_areas_created: 0,
84 neurons_created: 0,
85 synapses_created: 0,
86 duration_ms: 0,
87 }
88 }
89}
90
91pub struct Neuroembryogenesis {
99 connectome_manager: Arc<RwLock<ConnectomeManager>>,
101
102 progress: Arc<RwLock<DevelopmentProgress>>,
104
105 start_time: std::time::Instant,
107}
108
109impl Neuroembryogenesis {
110 pub fn new(connectome_manager: Arc<RwLock<ConnectomeManager>>) -> Self {
112 Self {
113 connectome_manager,
114 progress: Arc::new(RwLock::new(DevelopmentProgress::default())),
115 start_time: std::time::Instant::now(),
116 }
117 }
118
119 pub fn get_progress(&self) -> DevelopmentProgress {
121 self.progress.read().clone()
122 }
123
124 fn sync_core_neuron_params(&self, cortical_idx: u32, area: &CorticalArea) -> BduResult<()> {
128 use crate::models::CorticalAreaExt;
129
130 let npu_arc = {
131 let manager = self.connectome_manager.read();
132 manager
133 .get_npu()
134 .cloned()
135 .ok_or_else(|| BduError::Internal("NPU not connected".to_string()))?
136 };
137
138 let mut npu_lock = npu_arc
139 .lock()
140 .map_err(|e| BduError::Internal(format!("Failed to lock NPU: {}", e)))?;
141
142 npu_lock.update_cortical_area_threshold_with_gradient(
143 cortical_idx,
144 area.firing_threshold(),
145 area.firing_threshold_increment_x(),
146 area.firing_threshold_increment_y(),
147 area.firing_threshold_increment_z(),
148 );
149 npu_lock.update_cortical_area_threshold_limit(cortical_idx, area.firing_threshold_limit());
150 npu_lock.update_cortical_area_leak(cortical_idx, area.leak_coefficient());
151 npu_lock.update_cortical_area_excitability(cortical_idx, area.neuron_excitability());
152 npu_lock.update_cortical_area_refractory_period(cortical_idx, area.refractory_period());
153 npu_lock.update_cortical_area_consecutive_fire_limit(
154 cortical_idx,
155 area.consecutive_fire_count() as u16,
156 );
157 npu_lock.update_cortical_area_snooze_period(cortical_idx, area.snooze_period());
158 npu_lock.update_cortical_area_mp_charge_accumulation(
159 cortical_idx,
160 area.mp_charge_accumulation(),
161 );
162
163 Ok(())
164 }
165
166 pub fn add_cortical_areas(
178 &mut self,
179 areas: Vec<CorticalArea>,
180 genome: &RuntimeGenome,
181 ) -> BduResult<(usize, usize)> {
182 info!(target: "feagi-bdu", "🧬 Incrementally adding {} cortical areas", areas.len());
183
184 let mut total_neurons = 0;
185 let mut total_synapses = 0;
186
187 for area in &areas {
189 let mut manager = self.connectome_manager.write();
190 manager.add_cortical_area(area.clone())?;
191 info!(target: "feagi-bdu", " ✓ Added cortical area structure: {}", area.cortical_id.as_base_64());
192 }
193
194 use feagi_structures::genomic::cortical_area::CoreCorticalType;
197 let death_id = CoreCorticalType::Death.to_cortical_id();
198 let power_id = CoreCorticalType::Power.to_cortical_id();
199 let fatigue_id = CoreCorticalType::Fatigue.to_cortical_id();
200
201 let mut core_areas = Vec::new();
202 let mut other_areas = Vec::new();
203
204 for area in &areas {
206 if area.cortical_id == death_id {
207 core_areas.push((0, area)); } else if area.cortical_id == power_id {
209 core_areas.push((1, area)); } else if area.cortical_id == fatigue_id {
211 core_areas.push((2, area)); } else {
213 other_areas.push(area);
214 }
215 }
216
217 core_areas.sort_by_key(|(idx, _)| *idx);
219
220 if !core_areas.is_empty() {
222 info!(target: "feagi-bdu", " 🎯 Creating core area neurons FIRST ({} areas) for deterministic IDs", core_areas.len());
223 for (core_idx, area) in &core_areas {
224 let existing_core_neurons = {
225 let manager = self.connectome_manager.read();
226 let npu = manager.get_npu();
227 match npu {
228 Some(npu_arc) => {
229 let npu_lock = npu_arc.lock();
230 match npu_lock {
231 Ok(npu_guard) => {
232 npu_guard.get_neurons_in_cortical_area(*core_idx).len()
233 }
234 Err(_) => 0,
235 }
236 }
237 None => 0,
238 }
239 };
240
241 if existing_core_neurons > 0 {
242 self.sync_core_neuron_params(*core_idx, area)?;
243 let refreshed = {
244 let manager = self.connectome_manager.read();
245 manager.refresh_neuron_count_for_area(&area.cortical_id)
246 };
247 let count = refreshed.unwrap_or(existing_core_neurons);
248 total_neurons += count;
249 info!(
250 target: "feagi-bdu",
251 " ↪ Skipping core neuron creation for {} (existing={}, idx={})",
252 area.cortical_id.as_base_64(),
253 count,
254 core_idx
255 );
256 continue;
257 }
258 let neurons_created = {
259 let mut manager = self.connectome_manager.write();
260 manager.create_neurons_for_area(&area.cortical_id)
261 };
262
263 match neurons_created {
264 Ok(count) => {
265 total_neurons += count as usize;
266 info!(target: "feagi-bdu", " ✅ Created {} neurons for core area {} (deterministic ID: neuron {})",
267 count, area.cortical_id.as_base_64(), core_idx);
268 }
269 Err(e) => {
270 error!(target: "feagi-bdu", " ❌ FATAL: Failed to create neurons for core area {}: {}", area.cortical_id.as_base_64(), e);
271 return Err(e);
272 }
273 }
274 }
275 }
276
277 for area in &other_areas {
279 let neurons_created = {
280 let mut manager = self.connectome_manager.write();
281 manager.create_neurons_for_area(&area.cortical_id)
282 };
283
284 match neurons_created {
285 Ok(count) => {
286 total_neurons += count as usize;
287 trace!(
288 target: "feagi-bdu",
289 "Created {} neurons for area {}",
290 count,
291 area.cortical_id.as_base_64()
292 );
293 }
294 Err(e) => {
295 error!(target: "feagi-bdu", " ❌ FATAL: Failed to create neurons for {}: {}", area.cortical_id.as_base_64(), e);
296 return Err(e);
298 }
299 }
300 }
301
302 for area in &areas {
304 let has_dstmap = area
306 .properties
307 .get("cortical_mapping_dst")
308 .and_then(|v| v.as_object())
309 .map(|m| !m.is_empty())
310 .unwrap_or(false);
311
312 if !has_dstmap {
313 debug!(target: "feagi-bdu", " No mappings for area {}", area.cortical_id.as_base_64());
314 continue;
315 }
316
317 let synapses_created = {
318 let mut manager = self.connectome_manager.write();
319 manager.apply_cortical_mapping(&area.cortical_id)
320 };
321
322 match synapses_created {
323 Ok(count) => {
324 total_synapses += count as usize;
325 trace!(
326 target: "feagi-bdu",
327 "Created {} synapses for area {}",
328 count,
329 area.cortical_id
330 );
331 }
332 Err(e) => {
333 warn!(target: "feagi-bdu", " ⚠️ Failed to create synapses for {}: {}", area.cortical_id, e);
334 let estimated = estimate_synapses_for_area(area, genome);
335 total_synapses += estimated;
336 }
337 }
338 }
339
340 info!(target: "feagi-bdu", "✅ Incremental add complete: {} areas, {} neurons, {} synapses",
341 areas.len(), total_neurons, total_synapses);
342
343 Ok((total_neurons, total_synapses))
344 }
345
346 pub fn develop_from_genome(&mut self, genome: &RuntimeGenome) -> BduResult<()> {
350 info!(target: "feagi-bdu","🧬 Starting neuroembryogenesis for genome: {}", genome.metadata.genome_id);
351
352 let _quantization_precision = &genome.physiology.quantization_precision;
354 let quant_spec = QuantizationSpec::default();
356
357 info!(target: "feagi-bdu",
358 " Quantization precision: {:?} (range: [{}, {}] for membrane potential)",
359 quant_spec.precision,
360 quant_spec.membrane_potential_min,
361 quant_spec.membrane_potential_max
362 );
363
364 match quant_spec.precision {
368 Precision::FP32 => {
369 info!(target: "feagi-bdu", " ✓ Using FP32 (32-bit floating-point) - highest precision");
370 info!(target: "feagi-bdu", " Memory usage: Baseline (4 bytes/neuron for membrane potential)");
371 }
372 Precision::INT8 => {
373 info!(target: "feagi-bdu", " ✓ Using INT8 (8-bit integer) - memory efficient");
374 info!(target: "feagi-bdu", " Memory reduction: 42% (1 byte/neuron for membrane potential)");
375 info!(target: "feagi-bdu", " Quantization range: [{}, {}]",
376 quant_spec.membrane_potential_min,
377 quant_spec.membrane_potential_max);
378 }
381 Precision::FP16 => {
382 warn!(target: "feagi-bdu", " FP16 quantization requested but not yet implemented.");
383 warn!(target: "feagi-bdu", " FP16 support planned for future GPU optimization.");
384 }
386 }
387
388 info!(target: "feagi-bdu", " ✓ Quantization handled by DynamicNPU (dispatches at runtime)");
391
392 self.update_stage(DevelopmentStage::Initialization, 0);
394
395 self.corticogenesis(genome)?;
397
398 self.voxelogenesis(genome)?;
400
401 self.neurogenesis(genome)?;
403
404 self.synaptogenesis(genome)?;
406
407 self.update_stage(DevelopmentStage::Completed, 100);
409
410 let progress = self.progress.read();
411 info!(target: "feagi-bdu",
412 "✅ Neuroembryogenesis completed in {}ms: {} cortical areas, {} neurons, {} synapses",
413 progress.duration_ms,
414 progress.cortical_areas_created,
415 progress.neurons_created,
416 progress.synapses_created
417 );
418
419 Ok(())
420 }
421
422 fn corticogenesis(&mut self, genome: &RuntimeGenome) -> BduResult<()> {
424 self.update_stage(DevelopmentStage::Corticogenesis, 0);
425 info!(target: "feagi-bdu","🧠 Stage 1: Corticogenesis - Creating {} cortical areas", genome.cortical_areas.len());
426 info!(target: "feagi-bdu","🔍 Genome brain_regions check: is_empty={}, count={}",
427 genome.brain_regions.is_empty(), genome.brain_regions.len());
428 if !genome.brain_regions.is_empty() {
429 info!(target: "feagi-bdu"," Existing regions: {:?}", genome.brain_regions.keys().collect::<Vec<_>>());
430 }
431
432 let total_areas = genome.cortical_areas.len();
433
434 for (idx, (cortical_id, area)) in genome.cortical_areas.iter().enumerate() {
436 {
438 let mut manager = self.connectome_manager.write();
439 manager.add_cortical_area(area.clone())?;
440 } let progress_pct = ((idx + 1) * 100 / total_areas.max(1)) as u8;
444 self.update_progress(|p| {
445 p.cortical_areas_created = idx + 1;
446 p.progress = progress_pct;
447 });
448
449 trace!(target: "feagi-bdu", "Created cortical area: {} ({})", cortical_id, area.name);
450 }
451
452 info!(target: "feagi-bdu","🔍 BRAIN REGION AUTO-GEN CHECK: genome.brain_regions.is_empty() = {}", genome.brain_regions.is_empty());
455 let (brain_regions_to_add, region_parent_map) = if genome.brain_regions.is_empty() {
456 info!(target: "feagi-bdu"," ✅ TRIGGERING AUTO-GENERATION: No brain_regions in genome - auto-generating default root region");
457 info!(target: "feagi-bdu"," 📊 Genome has {} cortical areas to process", genome.cortical_areas.len());
458
459 let all_cortical_ids = genome.cortical_areas.keys().cloned().collect::<Vec<_>>();
461 info!(target: "feagi-bdu"," 📊 Collected {} cortical area IDs: {:?}", all_cortical_ids.len(),
462 if all_cortical_ids.len() <= 5 {
463 format!("{:?}", all_cortical_ids.iter().map(|id| id.to_string()).collect::<Vec<_>>())
464 } else {
465 format!("{:?}...", all_cortical_ids[0..5].iter().map(|id| id.to_string()).collect::<Vec<_>>())
466 });
467
468 let mut auto_inputs = Vec::new();
470 let mut auto_outputs = Vec::new();
471
472 let mut ipu_areas = Vec::new(); let mut opu_areas = Vec::new(); let mut core_areas = Vec::new(); let mut custom_memory_areas = Vec::new(); for (area_id, area) in genome.cortical_areas.iter() {
479 let area_id_str = area_id.to_string();
486 let category = if area_id_str.starts_with("___") {
488 "CORE"
489 } else if let Ok(cortical_type) = area.cortical_id.as_cortical_type() {
490 use feagi_structures::genomic::cortical_area::CorticalAreaType;
492 match cortical_type {
493 CorticalAreaType::Core(_) => "CORE",
494 CorticalAreaType::BrainInput(_) => "IPU",
495 CorticalAreaType::BrainOutput(_) => "OPU",
496 CorticalAreaType::Memory(_) => "MEMORY",
497 CorticalAreaType::Custom(_) => "CUSTOM",
498 }
499 } else {
500 let cortical_group = area
502 .properties
503 .get("cortical_group")
504 .and_then(|v| v.as_str())
505 .map(|s| s.to_uppercase());
506
507 match cortical_group.as_deref() {
508 Some("IPU") => "IPU",
509 Some("OPU") => "OPU",
510 Some("CORE") => "CORE",
511 Some("MEMORY") => "MEMORY",
512 Some("CUSTOM") => "CUSTOM",
513 _ => "CUSTOM", }
515 };
516
517 if ipu_areas.len() + opu_areas.len() + core_areas.len() + custom_memory_areas.len()
519 < 5
520 {
521 let source = if area.cortical_id.as_cortical_type().is_ok() {
522 "cortical_id_type"
523 } else if area.properties.contains_key("cortical_group") {
524 "cortical_group"
525 } else {
526 "default_fallback"
527 };
528
529 if area.cortical_id.as_cortical_type().is_ok() {
531 let type_desc = crate::cortical_type_utils::describe_cortical_type(area);
532 let frame_handling =
533 if crate::cortical_type_utils::uses_absolute_frames(area) {
534 "absolute"
535 } else if crate::cortical_type_utils::uses_incremental_frames(area) {
536 "incremental"
537 } else {
538 "n/a"
539 };
540 info!(target: "feagi-bdu"," 🔍 {}, frames={}, source={}",
541 type_desc, frame_handling, source);
542 } else {
543 info!(target: "feagi-bdu"," 🔍 Area {}: category={}, source={}",
544 area_id_str, category, source);
545 }
546 }
547
548 match category {
550 "IPU" => {
551 ipu_areas.push(*area_id);
552 auto_inputs.push(*area_id);
553 }
554 "OPU" => {
555 opu_areas.push(*area_id);
556 auto_outputs.push(*area_id);
557 }
558 "CORE" => {
559 core_areas.push(*area_id);
560 }
561 "MEMORY" | "CUSTOM" => {
562 custom_memory_areas.push(*area_id);
563 }
564 _ => {}
565 }
566 }
567
568 info!(target: "feagi-bdu"," 📊 Classification complete: IPU={}, OPU={}, CORE={}, CUSTOM/MEMORY={}",
569 ipu_areas.len(), opu_areas.len(), core_areas.len(), custom_memory_areas.len());
570
571 use feagi_structures::genomic::brain_regions::{BrainRegion, RegionID, RegionType};
573 let mut regions_map = std::collections::HashMap::new();
574
575 let mut root_area_ids = Vec::new();
577 root_area_ids.extend(ipu_areas.iter().cloned());
578 root_area_ids.extend(opu_areas.iter().cloned());
579 root_area_ids.extend(core_areas.iter().cloned());
580
581 let (root_inputs, root_outputs) =
583 Self::analyze_region_io(&root_area_ids, &genome.cortical_areas);
584
585 let root_region_id = RegionID::new();
588 let root_region_id_str = root_region_id.to_string();
589
590 let mut root_region = BrainRegion::new(
591 root_region_id,
592 "Root Brain Region".to_string(),
593 RegionType::Undefined,
594 )
595 .expect("Failed to create root region")
596 .with_areas(root_area_ids.iter().cloned());
597
598 if !root_inputs.is_empty() {
600 root_region
601 .add_property("inputs".to_string(), serde_json::json!(root_inputs.clone()));
602 }
603 if !root_outputs.is_empty() {
604 root_region.add_property(
605 "outputs".to_string(),
606 serde_json::json!(root_outputs.clone()),
607 );
608 }
609
610 info!(target: "feagi-bdu"," ✅ Created root region with {} areas (IPU={}, OPU={}, CORE={}) - analyzed: {} inputs, {} outputs",
611 root_area_ids.len(), ipu_areas.len(), opu_areas.len(), core_areas.len(),
612 root_inputs.len(), root_outputs.len());
613
614 let mut subregion_id = None;
616 if !custom_memory_areas.is_empty() {
617 let mut custom_memory_strs: Vec<String> = custom_memory_areas
619 .iter()
620 .map(|id| id.as_base_64())
621 .collect();
622 custom_memory_strs.sort(); let combined = custom_memory_strs.join("|");
624
625 use std::collections::hash_map::DefaultHasher;
627 use std::hash::{Hash, Hasher};
628 let mut hasher = DefaultHasher::new();
629 combined.hash(&mut hasher);
630 let hash = hasher.finish();
631 let hash_hex = format!("{:08x}", hash as u32);
632 let region_id = format!("region_autogen_{}", hash_hex);
633
634 let (subregion_inputs, subregion_outputs) =
636 Self::analyze_region_io(&custom_memory_areas, &genome.cortical_areas);
637
638 let autogen_position =
640 Self::calculate_autogen_region_position(&root_area_ids, genome);
641
642 let subregion_name = autogen_subregion_display_name(&genome.metadata.genome_title);
644 let mut subregion = BrainRegion::new(
645 RegionID::new(), subregion_name,
647 RegionType::Undefined, )
649 .expect("Failed to create subregion")
650 .with_areas(custom_memory_areas.iter().cloned());
651
652 subregion.add_property(
654 "coordinate_3d".to_string(),
655 serde_json::json!(autogen_position),
656 );
657 subregion.add_property("coordinate_2d".to_string(), serde_json::json!([0, 0]));
658
659 if !subregion_inputs.is_empty() {
661 subregion.add_property(
662 "inputs".to_string(),
663 serde_json::json!(subregion_inputs.clone()),
664 );
665 }
666 if !subregion_outputs.is_empty() {
667 subregion.add_property(
668 "outputs".to_string(),
669 serde_json::json!(subregion_outputs.clone()),
670 );
671 }
672
673 let subregion_id_str = subregion.region_id.to_string();
674
675 info!(target: "feagi-bdu"," ✅ Created subregion '{}' with {} CUSTOM/MEMORY areas ({} inputs, {} outputs)",
676 region_id, custom_memory_areas.len(), subregion_inputs.len(), subregion_outputs.len());
677
678 regions_map.insert(subregion_id_str.clone(), subregion);
679 subregion_id = Some(subregion_id_str);
680 }
681
682 regions_map.insert(root_region_id_str.clone(), root_region);
683
684 let total_inputs = root_inputs.len()
686 + if let Some(ref sid) = subregion_id {
687 regions_map
688 .get(sid)
689 .and_then(|r| r.properties.get("inputs"))
690 .and_then(|v| v.as_array())
691 .map(|a| a.len())
692 .unwrap_or(0)
693 } else {
694 0
695 };
696
697 let total_outputs = root_outputs.len()
698 + if let Some(ref sid) = subregion_id {
699 regions_map
700 .get(sid)
701 .and_then(|r| r.properties.get("outputs"))
702 .and_then(|v| v.as_array())
703 .map(|a| a.len())
704 .unwrap_or(0)
705 } else {
706 0
707 };
708
709 info!(target: "feagi-bdu"," ✅ Auto-generated {} brain region(s) with {} total cortical areas ({} total inputs, {} total outputs)",
710 regions_map.len(), all_cortical_ids.len(), total_inputs, total_outputs);
711
712 let mut parent_map = std::collections::HashMap::new();
714 if let Some(ref sub_id) = subregion_id {
715 parent_map.insert(sub_id.clone(), root_region_id_str.clone());
716 info!(target: "feagi-bdu"," 🔗 Parent relationship: {} -> {}", sub_id, root_region_id_str);
717 }
718
719 (regions_map, parent_map)
720 } else {
721 info!(target: "feagi-bdu"," 📋 Genome already has {} brain regions - using existing structure", genome.brain_regions.len());
722 let mut region_parent_map: std::collections::HashMap<String, String> =
726 std::collections::HashMap::new();
727 for (region_id, region) in &genome.brain_regions {
728 if let Some(pid) = region
729 .properties
730 .get("parent_region_id")
731 .and_then(|v| v.as_str())
732 {
733 region_parent_map.insert(region_id.clone(), pid.to_string());
734 }
735 }
736 if region_parent_map.is_empty() {
737 if let Some((root_id, _)) = genome
738 .brain_regions
739 .iter()
740 .find(|(_, r)| r.name == "Root Brain Region")
741 {
742 for (region_id, region) in &genome.brain_regions {
743 if region.name == "Root Brain Region" {
744 continue;
745 }
746 region_parent_map.insert(region_id.clone(), root_id.clone());
747 }
748 if !region_parent_map.is_empty() {
749 info!(target: "feagi-bdu",
750 " 🔗 Inferred {} sub-region parent link(s) under root {}",
751 region_parent_map.len(),
752 root_id
753 );
754 }
755 } else {
756 warn!(target: "feagi-bdu",
757 " ⚠️ brain_regions present but no 'Root Brain Region' and no parent_region_id — hierarchy may not load in BV"
758 );
759 }
760 }
761 (genome.brain_regions.clone(), region_parent_map)
762 };
763
764 {
766 let mut manager = self.connectome_manager.write();
767 let brain_region_count = brain_regions_to_add.len();
768 info!(target: "feagi-bdu"," Adding {} brain regions from genome", brain_region_count);
769
770 let root_entry = brain_regions_to_add
772 .iter()
773 .find(|(_, region)| region.name == "Root Brain Region");
774 if let Some((root_id, root_region)) = root_entry {
775 manager.add_brain_region(root_region.clone(), None)?;
776 debug!(target: "feagi-bdu"," ✓ Added brain region: {} (Root Brain Region) [parent=None]", root_id);
777 }
778
779 for (region_id, region) in brain_regions_to_add.iter() {
781 if region.name == "Root Brain Region" {
782 continue; }
784
785 let parent_id = region_parent_map.get(region_id).cloned();
786 manager.add_brain_region(region.clone(), parent_id.clone())?;
787 debug!(target: "feagi-bdu"," ✓ Added brain region: {} ({}) [parent={:?}]",
788 region_id, region.name, parent_id);
789 }
790
791 info!(target: "feagi-bdu"," Total brain regions in ConnectomeManager: {}", manager.get_brain_region_ids().len());
792 } self.update_stage(DevelopmentStage::Corticogenesis, 100);
795 info!(target: "feagi-bdu"," ✅ Corticogenesis complete: {} cortical areas created", total_areas);
796
797 Ok(())
798 }
799
800 fn voxelogenesis(&mut self, _genome: &RuntimeGenome) -> BduResult<()> {
802 self.update_stage(DevelopmentStage::Voxelogenesis, 0);
803 info!(target: "feagi-bdu","📐 Stage 2: Voxelogenesis - Establishing spatial framework");
804
805 self.update_stage(DevelopmentStage::Voxelogenesis, 100);
809 info!(target: "feagi-bdu"," ✅ Voxelogenesis complete: Spatial framework established");
810
811 Ok(())
812 }
813
814 fn neurogenesis(&mut self, genome: &RuntimeGenome) -> BduResult<()> {
823 self.update_stage(DevelopmentStage::Neurogenesis, 0);
824 info!(target: "feagi-bdu","🔬 Stage 3: Neurogenesis - Generating neurons (SIMD-optimized batches)");
825
826 let expected_neurons = genome.stats.innate_neuron_count;
827 info!(target: "feagi-bdu"," Expected innate neurons from genome: {}", expected_neurons);
828
829 use feagi_structures::genomic::cortical_area::CoreCorticalType;
831 let death_id = CoreCorticalType::Death.to_cortical_id();
832 let power_id = CoreCorticalType::Power.to_cortical_id();
833 let fatigue_id = CoreCorticalType::Fatigue.to_cortical_id();
834
835 let mut core_areas = Vec::new();
836 let mut other_areas = Vec::new();
837
838 for (cortical_id, area) in genome.cortical_areas.iter() {
840 if *cortical_id == death_id {
841 core_areas.push((0, *cortical_id, area)); } else if *cortical_id == power_id {
843 core_areas.push((1, *cortical_id, area)); } else if *cortical_id == fatigue_id {
845 core_areas.push((2, *cortical_id, area)); } else {
847 other_areas.push((*cortical_id, area));
848 }
849 }
850
851 core_areas.sort_by_key(|(idx, _, _)| *idx);
853
854 info!(target: "feagi-bdu"," 🎯 Creating core area neurons FIRST ({} areas) for deterministic IDs", core_areas.len());
855
856 let mut total_neurons_created = 0;
857 let mut processed_count = 0;
858 let total_areas = genome.cortical_areas.len();
859
860 for (core_idx, cortical_id, area) in &core_areas {
862 let existing_core_neurons = {
863 let manager = self.connectome_manager.read();
864 let npu = manager.get_npu();
865 match npu {
866 Some(npu_arc) => {
867 let npu_lock = npu_arc.lock();
868 match npu_lock {
869 Ok(npu_guard) => {
870 npu_guard.get_neurons_in_cortical_area(*core_idx).len()
871 }
872 Err(_) => 0,
873 }
874 }
875 None => 0,
876 }
877 };
878
879 if existing_core_neurons > 0 {
880 self.sync_core_neuron_params(*core_idx, area)?;
881 let refreshed = {
882 let manager = self.connectome_manager.read();
883 manager.refresh_neuron_count_for_area(cortical_id)
884 };
885 let count = refreshed.unwrap_or(existing_core_neurons);
886 total_neurons_created += count;
887 info!(
888 target: "feagi-bdu",
889 " ↪ Skipping core neuron creation for {} (existing={}, idx={})",
890 cortical_id.as_base_64(),
891 count,
892 core_idx
893 );
894 processed_count += 1;
895 let progress_pct = (processed_count * 100 / total_areas.max(1)) as u8;
896 self.update_progress(|p| {
897 p.neurons_created = total_neurons_created;
898 p.progress = progress_pct;
899 });
900 continue;
901 }
902 let per_voxel_count = area
903 .properties
904 .get("neurons_per_voxel")
905 .and_then(|v| v.as_u64())
906 .unwrap_or(1) as i64;
907
908 let cortical_id_str = cortical_id.to_string();
909 info!(target: "feagi-bdu"," 🔋 [CORE-AREA {}] {} - dimensions: {:?}, per_voxel: {}",
910 core_idx, cortical_id_str, area.dimensions, per_voxel_count);
911
912 if per_voxel_count == 0 {
913 warn!(target: "feagi-bdu"," ⚠️ Skipping core area {} - per_voxel_neuron_cnt is 0", cortical_id_str);
914 continue;
915 }
916
917 let neurons_created = {
919 let manager_arc = self.connectome_manager.clone();
920 let mut manager = manager_arc.write();
921 manager.create_neurons_for_area(cortical_id)
922 };
923
924 match neurons_created {
925 Ok(count) => {
926 total_neurons_created += count as usize;
927 info!(target: "feagi-bdu"," ✅ Created {} neurons for core area {} (deterministic ID: neuron {})",
928 count, cortical_id_str, core_idx);
929 }
930 Err(e) => {
931 error!(target: "feagi-bdu"," ❌ FATAL: Failed to create neurons for core area {}: {}", cortical_id_str, e);
932 return Err(e);
933 }
934 }
935
936 processed_count += 1;
937 let progress_pct = (processed_count * 100 / total_areas.max(1)) as u8;
938 self.update_progress(|p| {
939 p.neurons_created = total_neurons_created;
940 p.progress = progress_pct;
941 });
942 }
943
944 info!(target: "feagi-bdu"," 📦 Creating neurons for {} other areas", other_areas.len());
946 for (cortical_id, area) in &other_areas {
947 let _per_voxel_count = area
949 .properties
950 .get("neurons_per_voxel")
951 .and_then(|v| v.as_u64())
952 .unwrap_or(1) as i64;
953
954 let per_voxel_count = area
955 .properties
956 .get("neurons_per_voxel")
957 .and_then(|v| v.as_u64())
958 .unwrap_or(1) as i64;
959
960 let cortical_id_str = cortical_id.to_string();
961
962 if per_voxel_count == 0 {
963 warn!(target: "feagi-bdu"," ⚠️ Skipping area {} - per_voxel_neuron_cnt is 0 (will have NO neurons!)", cortical_id_str);
964 continue;
965 }
966
967 let neurons_created = {
970 let manager_arc = self.connectome_manager.clone();
971 let mut manager = manager_arc.write();
972 manager.create_neurons_for_area(cortical_id)
973 }; match neurons_created {
976 Ok(count) => {
977 total_neurons_created += count as usize;
978 trace!(
979 target: "feagi-bdu",
980 "Created {} neurons for area {}",
981 count,
982 cortical_id_str
983 );
984 }
985 Err(e) => {
986 warn!(target: "feagi-bdu"," Failed to create neurons for {}: {} (NPU may not be connected)",
988 cortical_id_str, e);
989 let total_voxels = area.dimensions.width as usize
990 * area.dimensions.height as usize
991 * area.dimensions.depth as usize;
992 let expected = total_voxels * per_voxel_count as usize;
993 total_neurons_created += expected;
994 }
995 }
996
997 processed_count += 1;
998 let progress_pct = (processed_count * 100 / total_areas.max(1)) as u8;
1000 self.update_progress(|p| {
1001 p.neurons_created = total_neurons_created;
1002 p.progress = progress_pct;
1003 });
1004 }
1005
1006 if expected_neurons > 0 && total_neurons_created != expected_neurons {
1008 trace!(target: "feagi-bdu",
1009 created_neurons = total_neurons_created,
1010 genome_stats_innate = expected_neurons,
1011 "Neuron creation complete (genome stats may only count innate neurons)"
1012 );
1013 }
1014
1015 self.update_stage(DevelopmentStage::Neurogenesis, 100);
1016 info!(target: "feagi-bdu"," ✅ Neurogenesis complete: {} neurons created", total_neurons_created);
1017
1018 Ok(())
1019 }
1020
1021 fn synaptogenesis(&mut self, genome: &RuntimeGenome) -> BduResult<()> {
1027 self.update_stage(DevelopmentStage::Synaptogenesis, 0);
1028 info!(target: "feagi-bdu","🔗 Stage 4: Synaptogenesis - Forming synaptic connections (SIMD-optimized batches)");
1029
1030 let expected_synapses = genome.stats.innate_synapse_count;
1031 info!(target: "feagi-bdu"," Expected innate synapses from genome: {}", expected_synapses);
1032
1033 self.rebuild_memory_twin_mappings_from_genome(genome)?;
1034
1035 let mut total_synapses_created = 0;
1036 let total_areas = genome.cortical_areas.len();
1037
1038 for (idx, (_src_cortical_id, src_area)) in genome.cortical_areas.iter().enumerate() {
1041 let has_dstmap = src_area
1043 .properties
1044 .get("cortical_mapping_dst")
1045 .and_then(|v| v.as_object())
1046 .map(|m| !m.is_empty())
1047 .unwrap_or(false);
1048
1049 if !has_dstmap {
1050 trace!(target: "feagi-bdu", "No dstmap for area {}", &src_area.cortical_id);
1051 continue;
1052 }
1053
1054 let src_cortical_id = &src_area.cortical_id;
1058 let src_cortical_id_str = src_cortical_id.to_string(); let synapses_created = {
1060 let manager_arc = self.connectome_manager.clone();
1061 let mut manager = manager_arc.write();
1062 if let Some(dstmap) = src_area.properties.get("cortical_mapping_dst") {
1063 if let Some(area) = manager.get_cortical_area_mut(src_cortical_id) {
1064 area.properties
1065 .insert("cortical_mapping_dst".to_string(), dstmap.clone());
1066 }
1067 }
1068 manager.apply_cortical_mapping(src_cortical_id)
1069 }; match synapses_created {
1072 Ok(count) => {
1073 total_synapses_created += count as usize;
1074 trace!(
1075 target: "feagi-bdu",
1076 "Created {} synapses for area {}",
1077 count,
1078 src_cortical_id_str
1079 );
1080 }
1081 Err(e) => {
1082 warn!(target: "feagi-bdu"," Failed to create synapses for {}: {} (NPU may not be connected)",
1084 src_cortical_id_str, e);
1085 let estimated = estimate_synapses_for_area(src_area, genome);
1086 total_synapses_created += estimated;
1087 }
1088 }
1089
1090 let progress_pct = ((idx + 1) * 100 / total_areas.max(1)) as u8;
1092 self.update_progress(|p| {
1093 p.synapses_created = total_synapses_created;
1094 p.progress = progress_pct;
1095 });
1096 }
1097
1098 let npu_arc = {
1103 let manager = self.connectome_manager.read();
1104 manager.get_npu().cloned()
1105 };
1106 if let Some(npu_arc) = npu_arc {
1107 let mut npu_lock = npu_arc
1108 .lock()
1109 .map_err(|e| BduError::Internal(format!("Failed to lock NPU: {}", e)))?;
1110 npu_lock.rebuild_synapse_index();
1111
1112 let manager = self.connectome_manager.read();
1114 manager.update_cached_synapse_count();
1115 }
1116
1117 #[cfg(feature = "plasticity")]
1120 {
1121 use feagi_evolutionary::extract_memory_properties;
1122 use feagi_npu_plasticity::{MemoryNeuronLifecycleConfig, PlasticityExecutor};
1123
1124 let manager = self.connectome_manager.read();
1125 if let Some(executor) = manager.get_plasticity_executor() {
1126 let mut registered_count = 0;
1127
1128 for area_id in manager.get_cortical_area_ids() {
1130 if let Some(area) = manager.get_cortical_area(area_id) {
1131 if let Some(mem_props) = extract_memory_properties(&area.properties) {
1132 let upstream_areas = manager.get_upstream_cortical_areas(area_id);
1133
1134 if let Some(npu_arc) = manager.get_npu() {
1137 if let Ok(mut npu) = npu_arc.lock() {
1138 let existing_configs = npu.get_all_fire_ledger_configs();
1139 for &upstream_idx in &upstream_areas {
1140 let existing = existing_configs
1141 .iter()
1142 .find(|(idx, _)| *idx == upstream_idx)
1143 .map(|(_, w)| *w)
1144 .unwrap_or(0);
1145
1146 let desired = mem_props.temporal_depth as usize;
1147 let resolved = existing.max(desired);
1148 if resolved != existing {
1149 if let Err(e) = npu.configure_fire_ledger_window(
1150 upstream_idx,
1151 resolved,
1152 ) {
1153 warn!(
1154 target: "feagi-bdu",
1155 "Failed to configure FireLedger window for upstream area idx={} (requested={}): {}",
1156 upstream_idx,
1157 resolved,
1158 e
1159 );
1160 }
1161 }
1162 }
1163 } else {
1164 warn!(target: "feagi-bdu", "Failed to lock NPU for FireLedger configuration");
1165 }
1166 }
1167
1168 if let Ok(exec) = executor.lock() {
1169 let upstream_non_memory =
1170 manager.filter_non_memory_upstream_areas(&upstream_areas);
1171 let lifecycle_config = MemoryNeuronLifecycleConfig {
1172 initial_lifespan: mem_props.init_lifespan,
1173 lifespan_growth_rate: mem_props.lifespan_growth_rate,
1174 longterm_threshold: mem_props.longterm_threshold,
1175 max_reactivations: 1000,
1176 };
1177
1178 exec.register_memory_area(
1179 area.cortical_idx,
1180 area_id.as_base_64(),
1181 mem_props.temporal_depth,
1182 upstream_non_memory,
1183 Some(lifecycle_config),
1184 );
1185
1186 registered_count += 1;
1187 }
1188 }
1189 }
1190 }
1191 let _ = registered_count; }
1193 }
1194
1195 if expected_synapses > 0 {
1197 let diff = (total_synapses_created as i64 - expected_synapses as i64).abs();
1198 let diff_pct = (diff as f64 / expected_synapses.max(1) as f64) * 100.0;
1199
1200 if diff_pct > 10.0 {
1201 warn!(target: "feagi-bdu",
1202 "Synapse count variance: created {} but genome stats expected {} ({:.1}% difference)",
1203 total_synapses_created, expected_synapses, diff_pct
1204 );
1205 } else {
1206 info!(target: "feagi-bdu",
1207 "Synapse count matches genome stats within {:.1}% ({} vs {})",
1208 diff_pct, total_synapses_created, expected_synapses
1209 );
1210 }
1211 }
1212
1213 self.update_stage(DevelopmentStage::Synaptogenesis, 100);
1214 info!(target: "feagi-bdu"," ✅ Synaptogenesis complete: {} synapses created", total_synapses_created);
1215
1216 Ok(())
1217 }
1218
1219 fn rebuild_memory_twin_mappings_from_genome(
1220 &mut self,
1221 genome: &RuntimeGenome,
1222 ) -> BduResult<()> {
1223 use feagi_structures::genomic::cortical_area::CorticalAreaType;
1224 let mut repaired = 0usize;
1225
1226 for (memory_id, memory_area) in genome.cortical_areas.iter() {
1227 let is_memory = matches!(
1228 memory_area.cortical_id.as_cortical_type(),
1229 Ok(CorticalAreaType::Memory(_))
1230 ) || memory_area
1231 .properties
1232 .get("is_mem_type")
1233 .and_then(|v| v.as_bool())
1234 .unwrap_or(false)
1235 || memory_area
1236 .properties
1237 .get("cortical_group")
1238 .and_then(|v| v.as_str())
1239 .is_some_and(|v| v.eq_ignore_ascii_case("MEMORY"));
1240 if !is_memory {
1241 continue;
1242 }
1243
1244 let Some(dstmap) = memory_area
1245 .properties
1246 .get("cortical_mapping_dst")
1247 .and_then(|v| v.as_object())
1248 else {
1249 continue;
1250 };
1251
1252 for (dst_id_str, rules) in dstmap {
1253 let Some(rule_array) = rules.as_array() else {
1254 continue;
1255 };
1256 let has_replay = rule_array.iter().any(|rule| {
1257 rule.get("morphology_id")
1258 .and_then(|v| v.as_str())
1259 .is_some_and(|id| id == "memory_replay")
1260 });
1261 if !has_replay {
1262 continue;
1263 }
1264
1265 let dst_id = match CorticalID::try_from_base_64(dst_id_str) {
1266 Ok(id) => id,
1267 Err(_) => {
1268 warn!(
1269 target: "feagi-bdu",
1270 "Invalid twin cortical ID in memory_replay dstmap: {}",
1271 dst_id_str
1272 );
1273 continue;
1274 }
1275 };
1276
1277 let Some(twin_area) = genome.cortical_areas.get(&dst_id) else {
1278 continue;
1279 };
1280 let Some(upstream_id_str) = twin_area
1281 .properties
1282 .get("memory_twin_of")
1283 .and_then(|v| v.as_str())
1284 else {
1285 continue;
1286 };
1287 let upstream_id = match CorticalID::try_from_base_64(upstream_id_str) {
1288 Ok(id) => id,
1289 Err(_) => {
1290 warn!(
1291 target: "feagi-bdu",
1292 "Invalid memory_twin_of value on twin area {}: {}",
1293 dst_id.as_base_64(),
1294 upstream_id_str
1295 );
1296 continue;
1297 }
1298 };
1299
1300 let mut manager = self.connectome_manager.write();
1301 if let Err(e) = manager.ensure_memory_twin_area(memory_id, &upstream_id) {
1302 warn!(
1303 target: "feagi-bdu",
1304 "Failed to rebuild memory twin mapping for memory {} upstream {}: {}",
1305 memory_id.as_base_64(),
1306 upstream_id.as_base_64(),
1307 e
1308 );
1309 continue;
1310 }
1311 repaired += 1;
1312 }
1313 }
1314
1315 info!(
1316 target: "feagi-bdu",
1317 "Rebuilt {} memory twin mapping(s) from genome",
1318 repaired
1319 );
1320 Ok(())
1321 }
1322}
1323
1324fn estimate_synapses_for_area(
1328 src_area: &CorticalArea,
1329 genome: &feagi_evolutionary::RuntimeGenome,
1330) -> usize {
1331 let dstmap = match src_area.properties.get("cortical_mapping_dst") {
1332 Some(serde_json::Value::Object(map)) => map,
1333 _ => return 0,
1334 };
1335
1336 let mut total = 0;
1337
1338 for (dst_id, rules) in dstmap {
1339 let dst_cortical_id = match feagi_evolutionary::string_to_cortical_id(dst_id) {
1341 Ok(id) => id,
1342 Err(_) => continue,
1343 };
1344 let dst_area = match genome.cortical_areas.get(&dst_cortical_id) {
1345 Some(area) => area,
1346 None => continue,
1347 };
1348
1349 let rules_array = match rules.as_array() {
1350 Some(arr) => arr,
1351 None => continue,
1352 };
1353
1354 for rule in rules_array {
1355 let morphology_id = rule
1356 .get("morphology_id")
1357 .and_then(|v| v.as_str())
1358 .unwrap_or("unknown");
1359 let scalar = rule
1360 .get("morphology_scalar")
1361 .and_then(|v| v.as_i64())
1362 .unwrap_or(1) as usize;
1363
1364 let src_per_voxel = src_area
1366 .properties
1367 .get("neurons_per_voxel")
1368 .and_then(|v| v.as_u64())
1369 .unwrap_or(1) as usize;
1370 let dst_per_voxel = dst_area
1371 .properties
1372 .get("neurons_per_voxel")
1373 .and_then(|v| v.as_u64())
1374 .unwrap_or(1) as usize;
1375
1376 let src_voxels =
1377 src_area.dimensions.width * src_area.dimensions.height * src_area.dimensions.depth;
1378 let dst_voxels =
1379 dst_area.dimensions.width * dst_area.dimensions.height * dst_area.dimensions.depth;
1380
1381 let src_neurons = src_voxels as usize * src_per_voxel;
1382 let dst_neurons = dst_voxels as usize * dst_per_voxel as usize;
1383
1384 let count = match morphology_id {
1386 "block_to_block" => src_neurons * dst_per_voxel * scalar,
1387 "projector" | "transpose_xy" | "transpose_yz" | "transpose_xz" => {
1388 src_neurons * dst_neurons * scalar
1389 }
1390 _ if morphology_id.contains("lateral") => src_neurons * scalar,
1391 _ => (src_neurons * scalar).min(src_neurons * dst_neurons / 10),
1392 };
1393
1394 total += count;
1395 }
1396 }
1397
1398 total
1399}
1400
1401impl Neuroembryogenesis {
1402 fn calculate_autogen_region_position(
1404 root_area_ids: &[CorticalID],
1405 genome: &feagi_evolutionary::RuntimeGenome,
1406 ) -> [i32; 3] {
1407 if root_area_ids.is_empty() {
1408 return [100, 0, 0];
1409 }
1410
1411 let mut min_x = i32::MAX;
1412 let mut max_x = i32::MIN;
1413 let mut min_y = i32::MAX;
1414 let mut max_y = i32::MIN;
1415 let mut min_z = i32::MAX;
1416 let mut max_z = i32::MIN;
1417
1418 for cortical_id in root_area_ids {
1419 if let Some(area) = genome.cortical_areas.get(cortical_id) {
1420 let pos: (i32, i32, i32) = area.position.into();
1421 let dims = (
1422 area.dimensions.width as i32,
1423 area.dimensions.height as i32,
1424 area.dimensions.depth as i32,
1425 );
1426
1427 min_x = min_x.min(pos.0);
1428 max_x = max_x.max(pos.0 + dims.0);
1429 min_y = min_y.min(pos.1);
1430 max_y = max_y.max(pos.1 + dims.1);
1431 min_z = min_z.min(pos.2);
1432 max_z = max_z.max(pos.2 + dims.2);
1433 }
1434 }
1435
1436 let bbox_width = (max_x - min_x).max(1);
1437 let padding = (bbox_width / 5).max(50);
1438 let autogen_x = max_x + padding;
1439 let autogen_y = (min_y + max_y) / 2;
1440 let autogen_z = (min_z + max_z) / 2;
1441
1442 info!(target: "feagi-bdu",
1443 " 📐 Autogen position: ({}, {}, {}) [padding: {}]",
1444 autogen_x, autogen_y, autogen_z, padding);
1445
1446 [autogen_x, autogen_y, autogen_z]
1447 }
1448
1449 fn analyze_region_io(
1455 region_area_ids: &[feagi_structures::genomic::cortical_area::CorticalID],
1456 all_cortical_areas: &std::collections::HashMap<CorticalID, CorticalArea>,
1457 ) -> (Vec<String>, Vec<String>) {
1458 let area_set: std::collections::HashSet<_> = region_area_ids.iter().cloned().collect();
1459 let mut inputs = Vec::new();
1460 let mut outputs = Vec::new();
1461
1462 let extract_destinations = |area: &CorticalArea| -> Vec<String> {
1464 area.properties
1465 .get("cortical_mapping_dst")
1466 .and_then(|v| v.as_object())
1467 .map(|obj| obj.keys().cloned().collect())
1468 .unwrap_or_default()
1469 };
1470
1471 for area_id in region_area_ids {
1473 if let Some(area) = all_cortical_areas.get(area_id) {
1474 let destinations = extract_destinations(area);
1475 let external_destinations: Vec<_> = destinations
1477 .iter()
1478 .filter_map(|dest| feagi_evolutionary::string_to_cortical_id(dest).ok())
1479 .filter(|dest_id| !area_set.contains(dest_id))
1480 .collect();
1481
1482 if !external_destinations.is_empty() {
1483 outputs.push(area_id.as_base_64());
1484 }
1485 }
1486 }
1487
1488 for (source_area_id, source_area) in all_cortical_areas.iter() {
1490 if area_set.contains(source_area_id) {
1492 continue;
1493 }
1494
1495 let destinations = extract_destinations(source_area);
1496 for dest_str in destinations {
1497 if let Ok(dest_id) = feagi_evolutionary::string_to_cortical_id(&dest_str) {
1498 if area_set.contains(&dest_id) {
1499 let dest_string = dest_id.as_base_64();
1500 if !inputs.contains(&dest_string) {
1501 inputs.push(dest_string);
1502 }
1503 }
1504 }
1505 }
1506 }
1507
1508 (inputs, outputs)
1509 }
1510
1511 fn update_stage(&self, stage: DevelopmentStage, progress: u8) {
1513 let mut p = self.progress.write();
1514 p.stage = stage;
1515 p.progress = progress;
1516 p.duration_ms = self.start_time.elapsed().as_millis() as u64;
1517 }
1518
1519 fn update_progress<F>(&self, f: F)
1521 where
1522 F: FnOnce(&mut DevelopmentProgress),
1523 {
1524 let mut p = self.progress.write();
1525 f(&mut p);
1526 p.duration_ms = self.start_time.elapsed().as_millis() as u64;
1527 }
1528}
1529
1530#[cfg(test)]
1531mod tests {
1532 use super::*;
1533 use feagi_evolutionary::create_genome_with_core_morphologies;
1534 use feagi_structures::genomic::cortical_area::CorticalAreaDimensions;
1535
1536 #[test]
1537 fn test_neuroembryogenesis_creation() {
1538 let manager = ConnectomeManager::instance();
1539 let neuro = Neuroembryogenesis::new(manager);
1540
1541 let progress = neuro.get_progress();
1542 assert_eq!(progress.stage, DevelopmentStage::Initialization);
1543 assert_eq!(progress.progress, 0);
1544 }
1545
1546 #[test]
1547 fn autogen_subregion_display_name_uses_title_when_meaningful() {
1548 assert_eq!(
1549 autogen_subregion_display_name("My Shared Circuit"),
1550 "My Shared Circuit"
1551 );
1552 }
1553
1554 #[test]
1555 fn autogen_subregion_display_name_falls_back_for_untitled() {
1556 assert_eq!(
1557 autogen_subregion_display_name("Untitled"),
1558 "Autogen Circuit"
1559 );
1560 assert_eq!(
1561 autogen_subregion_display_name("untitled"),
1562 "Autogen Circuit"
1563 );
1564 }
1565
1566 #[test]
1567 fn autogen_subregion_display_name_falls_back_for_blank() {
1568 assert_eq!(autogen_subregion_display_name(""), "Autogen Circuit");
1569 assert_eq!(autogen_subregion_display_name(" "), "Autogen Circuit");
1570 }
1571
1572 #[test]
1573 fn test_development_from_minimal_genome() {
1574 ConnectomeManager::reset_for_testing(); let manager = ConnectomeManager::instance();
1576 let mut neuro = Neuroembryogenesis::new(manager.clone());
1577
1578 let mut genome = create_genome_with_core_morphologies(
1580 "test_genome".to_string(),
1581 "Test Genome".to_string(),
1582 );
1583
1584 let cortical_id = CorticalID::try_from_bytes(b"cst_neur").unwrap(); let cortical_type = cortical_id
1586 .as_cortical_type()
1587 .expect("Failed to get cortical type");
1588 let area = CorticalArea::new(
1589 cortical_id,
1590 0,
1591 "Test Area".to_string(),
1592 CorticalAreaDimensions::new(10, 10, 10).unwrap(),
1593 (0, 0, 0).into(),
1594 cortical_type,
1595 )
1596 .expect("Failed to create cortical area");
1597 genome.cortical_areas.insert(cortical_id, area);
1598
1599 let result = neuro.develop_from_genome(&genome);
1601 assert!(result.is_ok(), "Development failed: {:?}", result);
1602
1603 let progress = neuro.get_progress();
1605 assert_eq!(progress.stage, DevelopmentStage::Completed);
1606 assert_eq!(progress.progress, 100);
1607 assert_eq!(progress.cortical_areas_created, 1);
1608
1609 println!("✅ Development completed in {}ms", progress.duration_ms);
1613 }
1614}