Executor-Tyrant-Framework Claude Opus 4.6 (1M context) commited on
Commit
7c57667
·
1 Parent(s): c85191b

Exorcise field ghosts: remove_region on free, dead allocations leave the field

Browse files

63,000 cold regions in the Lenia field were freed allocations that never
got removed. The field was paying to cool corpses — stepping temperature
on memory that no longer exists.

Fix: add LeniaField::remove_region(), wire into Pipeline::process_free().
Freed allocations are removed from the field, their energy reclaimed,
and their neighbor links cleaned up. The field only contains live memory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

rust_core/src/lenia.rs CHANGED
@@ -184,6 +184,24 @@ impl LeniaField {
184
  self.regions.insert(id, region);
185
  }
186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  /// Set neighborhood connections from graph edges
188
  pub fn set_neighbors(&mut self, id: u32, neighbors: Vec<(u32, f64)>) {
189
  self.neighbors.insert(id, neighbors);
 
184
  self.regions.insert(id, region);
185
  }
186
 
187
+ /// Remove a region from the field — called when an allocation is freed.
188
+ /// Reclaims the energy and removes from all tracking structures.
189
+ /// Dead allocations must not haunt the field.
190
+ pub fn remove_region(&mut self, id: u32) {
191
+ if let Some(region) = self.regions.remove(&id) {
192
+ let energy = region.temperature * (region.size_bytes as f64 / (1024.0 * 1024.0));
193
+ self.total_energy -= energy;
194
+ if self.total_energy < 0.0 {
195
+ self.total_energy = 0.0;
196
+ }
197
+ }
198
+ self.neighbors.remove(&id);
199
+ // Also remove this id from other regions' neighbor lists
200
+ for (_rid, nbrs) in self.neighbors.iter_mut() {
201
+ nbrs.retain(|(nid, _)| *nid != id);
202
+ }
203
+ }
204
+
205
  /// Set neighborhood connections from graph edges
206
  pub fn set_neighbors(&mut self, id: u32, neighbors: Vec<(u32, f64)>) {
207
  self.neighbors.insert(id, neighbors);
rust_core/src/pipeline.rs CHANGED
@@ -340,7 +340,10 @@ impl Pipeline {
340
  pub fn process_free(&mut self, address: usize) {
341
  self.condenser.unregister(address);
342
  self.address_to_path.remove(&address);
343
- self.address_to_field_id.remove(&address);
 
 
 
344
  }
345
 
346
  /// Rebuild the graph from accumulated events and retrain the predictor.
 
340
  pub fn process_free(&mut self, address: usize) {
341
  self.condenser.unregister(address);
342
  self.address_to_path.remove(&address);
343
+ // Remove from Lenia field — dead allocations don't get thermal cycles
344
+ if let Some(field_id) = self.address_to_field_id.remove(&address) {
345
+ self.field.remove_region(field_id);
346
+ }
347
  }
348
 
349
  /// Rebuild the graph from accumulated events and retrain the predictor.