""" Dynamic cell birth — logic for creating new cells when new knowledge patterns emerge during training. Design: - A "new pattern" = activation fingerprint that has low similarity (< threshold) to all patterns currently tracked by any cell. - When detected: create a new cell that SHARES the neuron range of a parent cell (logical birth, not physical). - The new cell gets: * Fresh DNA (mutated from parent) * Its own fp_history * Registered in plexus as a new node * Recorded in CognitiveLog """ from datetime import datetime, timezone from pathlib import Path from typing import Optional, Tuple from cells.saturation import Cell, MAX_CELLS_TOTAL from cells.dna_kernel import DNA, mutate_dna, random_dna # Global config NEW_PATTERN_THRESHOLD = 0.70 # similarity below this = new pattern MIN_SIMILAR_TO_ANY = 0.75 # if similarity to any cell's signature < this → potential birth BIRTH_COOLDOWN_STEPS = 100 # min steps between births for the same layer class BirthRegistry: """Tracks births and enforces cooldown.""" def __init__(self): self.last_birth_step = {} # layer_idx -> step self.birth_counter = 0 def can_birth(self, layer_idx: int, current_step: int) -> bool: last = self.last_birth_step.get(layer_idx, -10**9) return (current_step - last) >= BIRTH_COOLDOWN_STEPS def mark_birth(self, layer_idx: int, current_step: int): self.last_birth_step[layer_idx] = current_step self.birth_counter += 1 def birth_from_pattern( parent_cell: Cell, parent_dna: DNA, new_pattern_sig: str, step: int, model_uuid: str = "mother-001", registry: Optional[BirthRegistry] = None, ) -> Tuple[Cell, DNA]: """ Create a new cell from a parent, sharing its neuron range. Returns: (new_cell, new_dna) """ if registry is not None and not registry.can_birth(parent_cell.layer_idx, step): return None, None # Cell ID: extension of parent child_index = parent_cell.splits + 1 new_id = f"{parent_cell.cell_id}-b{child_index:02d}" new_cell = Cell( cell_id=new_id, layer_idx=parent_cell.layer_idx, neuron_start=parent_cell.neuron_start, neuron_end=parent_cell.neuron_end, state="active", parent_id=parent_cell.cell_id, created_at=datetime.now(timezone.utc).isoformat(), last_updated_step=step, fp_history=[new_pattern_sig], pattern_sig=new_pattern_sig, ) # Mutated DNA from parent new_dna = mutate_dna(parent_dna, rate=0.03) new_dna.cell_id = new_id if registry is not None: registry.mark_birth(parent_cell.layer_idx, step) return new_cell, new_dna def find_birth_candidate( pattern_sig: str, cells_in_layer: list, hamming_similarity_fn, threshold: float = MIN_SIMILAR_TO_ANY, ) -> Optional[Cell]: """ Find a cell whose pattern_sig is closest to the new pattern. If even the closest is below threshold, return None (no good parent). Otherwise, return the closest cell as candidate parent. """ best = None best_sim = -1.0 for c in cells_in_layer: if c.state != "active": continue if not c.pattern_sig: # Cell has no pattern yet — can be parent return c sim = hamming_similarity_fn(pattern_sig, c.pattern_sig) if sim > best_sim: best_sim = sim best = c if best is None: return None if best_sim < threshold: # No cell is close enough — skip birth (pattern too foreign) return None return best if __name__ == "__main__": # Standalone test import sys sys.path.insert(0, "/data/berna-r7/core/code") from cognitive_log import pattern_signature, hamming_similarity # Build a fake parent parent = Cell(cell_id="test-000", layer_idx=0, neuron_start=0, neuron_end=1536) parent_dna = random_dna(parent.cell_id, seed=42) reg = BirthRegistry() new_cell, new_dna = birth_from_pattern( parent_cell=parent, parent_dna=parent_dna, new_pattern_sig="abcdef0123456789", step=100, registry=reg, ) print(f"Birth OK: {new_cell.cell_id} (parent={new_cell.parent_id})") print(f"DNA signature: {new_dna.signature[:16]}") print(f"Births in registry: {reg.birth_counter}") # Second birth same layer within cooldown → rejected new_cell2, _ = birth_from_pattern( parent_cell=parent, parent_dna=parent_dna, new_pattern_sig="1234567890abcdef", step=150, # only 50 steps later registry=reg, ) print(f"Cooldown block: {new_cell2 is None}") # R8 anti-explosion cap (added 12 Oct 2026) MAX_CELLS_PER_LAYER = 120 # R8 anti-explosion cap