# Batch-D Integration Notes

Two new modules added in this batch.  Neither modifies existing files.

---

## Module 1 — `src/talon_federated.{h,cpp}`

### Wire type
`MSG_TYPE_FED_UPDATE = 0x1B`

### main.cpp dispatch addition
Add to the `switch (msg_type)` block in `loop()`:

```cpp
case MSG_TYPE_FED_UPDATE:                       // 0x1B
    talon_handle_chunk(rx_buf, (size_t)rx_len);
    break;
```

Add to `setup()` after `ffps_init()`:

```cpp
talon_init();
```

Add to `loop()` after the FFPS tick (step 2), before spectrum capture:

```cpp
if (talon_round_complete()) {
    if (talon_apply_round()) {
        Serial.printf("[%s] TALON fed-round %u applied\n",
                      TAG, (unsigned)talon_current_round());
    } else {
        Serial.printf("[%s] TALON fed-round %u apply FAILED\n",
                      TAG, (unsigned)talon_current_round());
    }
}
```

### config.h addition
Add after the existing `MSG_TYPE_*` defines:

```c
#define MSG_TYPE_FED_UPDATE    0x1B  // T2 -> T1: federated weight-delta chunk
```

### PSRAM budget
`talon_init()` allocates 64 KB from SPIRAM once at boot.  This is within the
existing `MODEL_PSRAM_BUDGET` (4 MB) with ample headroom.

### v1 scope cuts (documented here for patent and v2 planning)
- **TALON push side** — on-device gradient computation requires int8 backprop
  through model_manager's TFLite-Micro inference path.  The gradient callback
  API does not yet exist in model_manager.  Deferred to v2.
  Stubs: `talon_collect_local_anchors()`, `talon_compute_gradient()`.
- **Ed25519 signed FED_UPDATE** — v1 chunks carry no signature field.
  `talon_apply_round()` rejects if an Ed25519 key has been provisioned in NVS
  (conservative-fail posture).  The integrator must not provision a key until
  v2 signed FED_UPDATE packets are deployed.

---

## Module 2 — `src/cognitive_rf.{h,cpp}`

### Wire type
`MSG_TYPE_COGNITIVE_RF = 0x1C`

### config.h addition
Add after the existing `MSG_TYPE_*` defines:

```c
#define MSG_TYPE_COGNITIVE_RF  0x1C  // T1 -> T2: per-channel EWMA baselines
```

### main.cpp additions

In `setup()` after `wfx_features_init()`:

```cpp
cogrf_init();
```

In `wifi_sniffer_cb()`, after the existing RSSI EMA update:

```cpp
cogrf_observe(ch, rssi);
```

In `loop()` every 300 cycles (~5 min at 1 Hz):

```cpp
if (s_loop_count % 300 == 0) {
    cogrf_publish(s_sensor_id);
    mesh_start_receive();
}
```

Optionally, in the post-FFPS detection path (after `ffps_submit_candidate()`):

```cpp
uint8_t cogrf_ch;  float cogrf_score;
if (cogrf_anomalous_emitter(&cogrf_ch, &cogrf_score)) {
    Serial.printf("[%s] CogRF anomaly ch=%u score=%.1f\n",
                  TAG, cogrf_ch, cogrf_score);
}
```

### Memory footprint (SRAM only — no PSRAM allocation)

| Structure              | Size       |
|------------------------|------------|
| `s_ewma[13]`           | 52 bytes   |
| `s_ewma_var[13]`       | 52 bytes   |
| `s_obs_count[13]`      | 26 bytes   |
| `s_ring[13][60]`       | 1,560 bytes|
| `s_ring_head[13]`      | 13 bytes   |
| `s_cusum[13]`          | 52 bytes   |
| `s_anomaly_flag[13]`   | 13 bytes   |
| `pkt[76]` (publish)    | 76 bytes   |
| **Total**              | **~1,844 bytes** |

This fits comfortably within the ESP32-S3's 512 KB SRAM with well under 1%
of available SRAM consumed.

### v1 scope cuts
- **SVD / Blind Source Separation** (`TensorNetworkBSS` in Python) — requires
  floating-point matrix operations not feasible in the hot RSSI callback path.
  Runs server-side on Jetson-SIGINT or DGX via the existing cognitive_rf.py.
- **EmitterKnowledgeGraph** — SQLite persistence; runs on Jetson-SIGINT.
- **TemporalPatternMiner** — FFT autocorrelation; runs on Jetson-SIGINT.
- **Diurnal segmentation** — the Python learner segments EWMA by 4-hour
  time bins; the ESP32 maintains a single global EWMA per channel (no RTC
  epoch available without GPS fix).

---

## Running the native tests

```
pio test -e native -f test_batch_d
```

Expected output: `4 Tests 0 Failures 0 Ignored`

The `test_filter` in `platformio.ini` must include `test_batch_d`.
See the platformio.ini update instruction in this same batch.
