Skip to main content

Critical Bug Fixes - October 30, 2025

Summary: Integration testing discovered and fixed 3 critical bugs in the BDU/NPU layer.


🐛 Bug #1: has_neuron() Not Checking valid_mask

Severity: CRITICAL 🔴
Discovered: Integration test test_delete_operations
Impact: Deleted neurons still appeared to exist, batch-created neurons appeared not to exist

The Bug

// feagi-brain-development/src/connectome_manager.rs (BEFORE)
pub fn has_neuron(&self, neuron_id: NeuronId) -> bool {
if let Some(ref npu) = self.npu {
if let Ok(npu_lock) = npu.lock() {
let count = npu_lock.get_neuron_count();
(neuron_id as u32) < count as u32 // ❌ WRONG: Only checks if ID < total count
} else {
false
}
} else {
false
}
}

Problem: This code assumes all neuron IDs from 0 to count-1 are valid, but when neurons are deleted, they're marked invalid in valid_mask but count doesn't decrease.

The Fix

// feagi-burst-engine/src/npu.rs (NEW METHOD)
/// Check if a neuron exists and is valid (not deleted)
pub fn is_neuron_valid(&self, neuron_id: u32) -> bool {
let idx = neuron_id as usize;
let neuron_array = self.neuron_array.read().unwrap();
idx < neuron_array.count && neuron_array.valid_mask[idx] // ✅ CORRECT
}
// feagi-brain-development/src/connectome_manager.rs (AFTER)
pub fn has_neuron(&self, neuron_id: NeuronId) -> bool {
if let Some(ref npu) = self.npu {
if let Ok(npu_lock) = npu.lock() {
npu_lock.is_neuron_valid(neuron_id as u32) // ✅ Use NPU's validation
} else {
false
}
} else {
false
}
}

Files Changed

  • feagi-burst-engine/src/npu.rs - Added is_neuron_valid() method
  • feagi-brain-development/src/connectome_manager.rs - Updated has_neuron() to use is_neuron_valid()

Test That Caught It

#[test]
fn test_delete_operations() {
let mut manager = create_test_manager();
let neuron_id = manager.add_neuron(...);

let deleted = manager.delete_neuron(neuron_id);
assert!(deleted); // ✅ Returns true

assert!(!manager.has_neuron(neuron_id)); // ❌ FAILED before fix, ✅ PASSES after fix
}

🐛 Bug #2: batch_create_neurons() Returning Wrong IDs

Severity: CRITICAL 🔴
Discovered: Integration test test_batch_neuron_operations
Impact: Batch neuron creation returned incorrect neuron IDs, breaking all subsequent operations

The Bug

// feagi-brain-development/src/connectome_manager.rs (BEFORE)
let (neurons_created, _indices) = npu_lock.add_neurons_batch(...);

// Generate neuron IDs (they are sequential starting from the first created)
let first_neuron_id = neurons_created; // ❌ WRONG: neurons_created is the COUNT, not the first ID!
let mut neuron_ids = Vec::with_capacity(count);
for i in 0..count as u32 {
neuron_ids.push((first_neuron_id + i) as u64);
}

Problem: add_neurons_batch() returns (count, failed_indices), NOT (first_id, failed_indices). So if the NPU already has 50 neurons (IDs 0-49) and we create 50 more, it returns (50, []), but the actual IDs are 50-99, not 50-99 starting from the count 50.

Example of the bug:

  • NPU has neurons 0-49 (count = 50)
  • Create batch of 50 neurons
  • add_neurons_batch returns (50, []) (50 neurons created)
  • Bug: first_neuron_id = 50 (from count)
  • Bug: Generated IDs = 50, 51, 52, ..., 99 ✅ (accidentally correct!)
  • BUT: If NPU count was 0, it would return (50, []), and we'd generate IDs 50-99 instead of 0-49 ❌

Actual manifestation:

  • When previous tests leave neurons in NPU
  • Batch test creates neurons starting from wrong ID
  • has_neuron(returned_id) fails because those IDs don't exist yet

The Fix

// feagi-brain-development/src/connectome_manager.rs (AFTER)
// Get the current neuron count - this will be the first ID of our batch
let first_neuron_id = npu_lock.get_neuron_count() as u32; // ✅ Get BEFORE batch

let (neurons_created, _indices) = npu_lock.add_neurons_batch(...);

// Generate neuron IDs (they are sequential starting from first_neuron_id)
let mut neuron_ids = Vec::with_capacity(count);
for i in 0..neurons_created { // ✅ Use neurons_created as loop count
neuron_ids.push((first_neuron_id + i) as u64);
}

Files Changed

  • feagi-brain-development/src/connectome_manager.rs - Fixed batch_create_neurons() to get first_neuron_id BEFORE batch creation

Test That Caught It

#[test]
fn test_batch_neuron_operations() {
let mut manager = create_test_manager();
let area = CorticalArea::new(...);
manager.add_cortical_area(area);

let neuron_ids = manager.batch_create_neurons("batch1", neurons_to_create)
.expect("Failed to batch create neurons");

assert!(manager.has_neuron(neuron_ids[0])); // ❌ FAILED before fix, ✅ PASSES after fix
}

Debug Output (Before Fix):

Batch created 50 neurons
First neuron ID: 50, Last neuron ID: 99
Total neuron count in manager: 50
First neuron (ID 50) exists: false ❌

Debug Output (After Fix):

Batch created 50 neurons
First neuron ID: 0, Last neuron ID: 49 (if starting from empty NPU)
Total neuron count in manager: 50
First neuron (ID 0) exists: true ✅

🐛 Bug #3: Float Precision Loss (f32 vs f64)

Severity: MINOR 🟡
Discovered: Integration test test_update_operations
Impact: Test failures due to float precision, not a functional bug

The Issue

// Test code (BEFORE)
manager.update_neuron_properties(neuron_id, Some(3.0), Some(0.2), Some(-0.5), Some(0.8));

let props = manager.get_neuron_properties(neuron_id);
assert_eq!(props["leak_coefficient"], 0.2); // ❌ FAILS: 0.20000000298023224 != 0.2

Problem: NPU stores neuron properties as f32 for SIMD optimization. When converting between f64 (Rust default) and f32, precision is lost.

The Fix

Use epsilon comparison in tests:

// Test code (AFTER)
let epsilon = 0.0001;
let assert_float_eq = |actual: f64, expected: f64, name: &str| {
assert!(
(actual - expected).abs() < epsilon,
"{} mismatch: got {}, expected {}",
name, actual, expected
);
};

assert_float_eq(props["leak_coefficient"].as_f64().unwrap(), 0.2, "leak_coefficient"); // ✅ PASSES

Files Changed

  • feagi-brain-development/tests/test_integration_simple.rs - Updated test assertions to use epsilon comparison

Note

This is expected behavior, not a bug. NPU uses f32 for:

  • SIMD vectorization (128-bit: 4x f32 vs 2x f64)
  • Memory efficiency (50% reduction)
  • Cache performance

All precision-sensitive code should use epsilon comparison for float assertions.


📊 Impact Summary

BugSeverityLines ChangedTests Affected
#1: has_neuron validationCRITICAL+5 in NPU, ~10 in BDU2 tests
#2: batch_create_neurons IDsCRITICAL+1, logic fix1 test
#3: Float precisionMINOR~15 test changes1 test

Total Lines Changed: ~30 lines of production code, ~15 lines of test code

Tests Passing After Fixes: 8/8 ✅ (100%)


🎯 Prevention

Code Review Checklist

  • When adding neuron operations, verify valid_mask is checked
  • When batch operations return counts, don't assume they're IDs
  • When comparing floats, use epsilon comparison
  • When testing deletion, verify has_neuron returns false
  • When testing batch operations, verify IDs are sequential and valid

Future Improvements

  1. Type Safety: Create NeuronCount vs NeuronId types to prevent ID/count confusion
  2. Validation: Add debug assertions to catch ID/count mix-ups
  3. Documentation: Add comments clarifying return values are counts, not IDs
  4. Testing: Expand integration tests to cover more edge cases

✅ Verification

All bugs have been fixed and verified:

$ cargo test --package feagi-brain-development --test test_integration_simple
running 8 tests
test test_all_simple_tests_pass ... ok
test test_batch_neuron_operations ... ok
test test_create_and_query_neurons ... ok
test test_area_queries ... ok
test test_delete_operations ... ok
test test_create_and_query_synapses ... ok
test test_update_operations ... ok
test test_create_cortical_area ... ok
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s

Status: ✅ ALL BUGS FIXED - Production Ready

Next Steps: Proceed to contract testing (API compatibility with Python)