## PR — Fix C++ build: break header-cycle in `SlotEngine`, silence demo `prune(...)`, tidy warnings

### Why

- **Header-cycle**: `Neuron.h` includes `SlotEngine.h`, and `SlotEngine.h`’s inline `selectOrCreateSlot2D(...)` touches `Neuron` members (`anchorRow`, `anchorCol`, `getSlots()`). Because `Neuron` is only forward-declared at that point, the compiler sees an incomplete type and fails.
   **Fix:** move the definition of `selectOrCreateSlot2D(...)` into `SlotEngine.cpp` (where we can include `Neuron.h`) and keep only its declaration in the header.
- **Demo prune calls**: several demo mains call `region.prune(...)`, which isn’t present in the C++ build right now.
   **Fix:** comment those lines out (documented no-op), so the demos still build and run.
- **Warnings**: clean up two misleading-indentation spots in `Region.cpp`.

------

### 1) `src/cpp/SlotEngine.h` — move `selectOrCreateSlot2D` out of the header

```diff
--- a/src/cpp/SlotEngine.h
+++ b/src/cpp/SlotEngine.h
@@
-#pragma once
-#include <utility>
-#include <cmath>
-#include "Weight.h"
-#include "SlotConfig.h"
-class Neuron; // forward decl
+#pragma once
+#include <utility>
+#include <cmath>
+#include "Weight.h"
+#include "SlotConfig.h"
+class Neuron; // forward decl (avoid pulling Neuron.h into this header)

 struct SlotEngine {
     SlotConfig cfg;
@@
     inline std::pair<int,int> slotId2D(int anchorRow, int anchorCol, int row, int col) const {
         const double eps   = std::max(1e-12, cfg.epsilonScale);
         const double denomR = std::max(std::abs(static_cast<double>(anchorRow)), eps);
         const double denomC = std::max(std::abs(static_cast<double>(anchorCol)), eps);
         const double dpr = std::abs(static_cast<double>(row - anchorRow)) * 100.0 / denomR;
         const double dpc = std::abs(static_cast<double>(col - anchorCol)) * 100.0 / denomC;
         const double bwR = std::max(0.1, cfg.binWidthPct);
         const double bwC = std::max(0.1, cfg.binWidthPct);
         return { static_cast<int>(std::floor(dpr / bwR)),
                  static_cast<int>(std::floor(dpc / bwC)) };
     }
 
-    inline Weight& selectOrCreateSlot2D(Neuron& neuron, int row, int col) const {
-        // FIRST-anchor semantics on (row,col)
-        if (neuron.anchorRow < 0 || neuron.anchorCol < 0) {
-            neuron.anchorRow = row; neuron.anchorCol = col;
-        }
-        auto rc = slotId2D(neuron.anchorRow, neuron.anchorCol, row, col);
-        int limit = cfg.slotLimit > 0 ? cfg.slotLimit : 0x7fffffff;
-        int rb = std::min(rc.first,  limit - 1);
-        int cb = std::min(rc.second, limit - 1);
-        int key = rb * 100000 + cb; // simple packing
-        auto& slots = neuron.getSlots();
-        auto it = slots.find(key);
-        if (it == slots.end()) it = slots.emplace(key, Weight{}).first;
-        return it->second;
-    }
+    // Implemented in SlotEngine.cpp (requires the full Neuron definition)
+    Weight& selectOrCreateSlot2D(Neuron& neuron, int row, int col) const;
 };
```

------

### 2) `src/cpp/SlotEngine.cpp` — provide the out‑of‑line definition

```diff
--- a/src/cpp/SlotEngine.cpp
+++ b/src/cpp/SlotEngine.cpp
@@
+#include "SlotEngine.h"
+#include "Neuron.h"
+#include <algorithm>
+#include <climits>
+
+namespace grownet {
+
+Weight& SlotEngine::selectOrCreateSlot2D(Neuron& neuron, int row, int col) const {
+    // FIRST-anchor semantics on (row,col)
+    if (neuron.anchorRow < 0 || neuron.anchorCol < 0) {
+        neuron.anchorRow = row;
+        neuron.anchorCol = col;
+    }
+
+    auto rc = slotId2D(neuron.anchorRow, neuron.anchorCol, row, col);
+    const int limit = (cfg.slotLimit > 0) ? cfg.slotLimit : INT_MAX;
+    const int rb = std::min(rc.first,  limit - 1);
+    const int cb = std::min(rc.second, limit - 1);
+    const int key = rb * 100000 + cb; // simple packing
+
+    auto& slots = neuron.getSlots();
+    auto it = slots.find(key);
+    if (it == slots.end()) {
+        it = slots.emplace(key, Weight{}).first;
+    }
+    return it->second;
+}
+
+} // namespace grownet
```

*(If your `SlotEngine.cpp` already includes other code, just add the `#include "Neuron.h"` and the function body above under the `grownet` namespace.)*

------

### 3) `src/cpp/DemoMain.cpp` — comment the `prune(...)` call

```diff
--- a/src/cpp/DemoMain.cpp
+++ b/src/cpp/DemoMain.cpp
@@
-    auto pruneSummary = region.prune(10000, 0.05);
+    // NOTE: Region::prune(...) is not available in this build; skipping in demo.
+    // auto pruneSummary = region.prune(10000, 0.05);
```

------

### 4) `src/cpp/RegionDemo.cpp` — comment the `prune(...)` call

```diff
--- a/src/cpp/RegionDemo.cpp
+++ b/src/cpp/RegionDemo.cpp
@@
-    auto pruneSummary = region.prune(10000, 0.05);
+    // NOTE: Region::prune(...) is not available in this build; skipping in demo.
+    // auto pruneSummary = region.prune(10000, 0.05);
```

------

### 5) `src/cpp/demo/region_demo.cpp` — comment the `prune(...)` call

```diff
--- a/src/cpp/demo/region_demo.cpp
+++ b/src/cpp/demo/region_demo.cpp
@@
-    PruneSummary summary = region.prune(10'000, 0.05, 10'000, 0.05);
+    // NOTE: Region::prune(...) is not available in this build; skipping in demo.
+    // PruneSummary summary = region.prune(10'000, 0.05, 10'000, 0.05);
```

------

### 6) `src/cpp/Region.cpp` — tidy misleading‑indentation warnings

```diff
--- a/src/cpp/Region.cpp
+++ b/src/cpp/Region.cpp
@@
-            auto isAllZero = [](const std::vector<std::vector<double>>& img) {
-                for (const auto& row : img) for (double v : row) if (v != 0.0) return false; return true;
-            };
+            auto isAllZero = [](const std::vector<std::vector<double>>& img) {
+                for (const auto& row : img) {
+                    for (double v : row) {
+                        if (v != 0.0) return false;
+                    }
+                }
+                return true;
+            };
@@
-                    if (v > 0.0) {
-                        ++active; total += v; sumR += r * v; sumC += c * v;
-                        if (r < rmin) rmin = r; if (r > rmax) rmax = r;
-                        if (c < cmin) cmin = c; if (c > cmax) cmax = c;
-                    }
+                    if (v > 0.0) {
+                        ++active;
+                        total += v;
+                        sumR += r * v;
+                        sumC += c * v;
+                        if (r < rmin) rmin = r;
+                        if (r > rmax) rmax = r;
+                        if (c < cmin) cmin = c;
+                        if (c > cmax) cmax = c;
+                    }
```

------

## What this PR changes (behavior)

- **No functional changes**. It only relocates code to fix the header-cycle and comments out demo-only calls to a method that isn’t compiled in this build.
- Keeps your **spatial slotting** path intact and the **windowed wiring** logic unchanged.

## Why this works

- Moving `selectOrCreateSlot2D(...)` out of the header lets it **see the full `Neuron` definition** via `#include "Neuron.h"` in the `.cpp`. That resolves all the “invalid use of incomplete type 'class Neuron'” errors that appeared in multiple translation units (`ModulatoryNeuron.cpp`, `InhibitoryNeuron.cpp`, `ExcitatoryNeuron.cpp`, `Neuron.cpp`, `Layer.cpp`, etc.).
- Commenting out `region.prune(...)` in demos unblocks the build without forcing new API surface.

## Optional follow‑ups (when convenient)

- If you want the prune calls back, we can add a **tiny `Region::prune(...)` stub** that walks layers and calls a per-neuron `pruneSynapses(...)` (you already do that in Python). I can draft that once you confirm the desired signature.

- If you prefer demos to compile with strict warnings-as-errors, we can also silence the **unused variable** in `tests/region_tick_tests.cpp` by replacing:

  ```cpp
  Tract& t = region.connectLayers(src, dst, 1.0, false);
  ```

  with:

  ```cpp
  (void)region.connectLayers(src, dst, 1.0, false);
  ```

  (or keep the reference and add `(void)t;`).

------

