ble-reticulum/migration/phase2/Gate2D_BLEPeerSessionManager_python_equivalence_20260518_1611.md

132 lines
4.8 KiB
Markdown
Raw Normal View History

# Gate 2D: BLEPeerSessionManager Python Equivalence
Date: 2026-05-18 16:11 America/Los_Angeles
Scope: Python equivalence harness only. No live BLE integration.
## Summary
Gate 2D added a Python test harness that compares current Python
`BLEInterface._handle_identity_handshake` behavior with the C++
`BLEPeerSessionManager` pybind decision/result model.
Added:
- `migration/tests/test_ble_peer_session_manager_python_equivalence.py`
- `migration/phase2/Gate2D_BLEPeerSessionManager_python_equivalence_20260518_1611.md`
- `migration/sql/mark_gate2d_protocol_session_python_equivalence_20260518_1611.sql`
Unchanged:
- `src/ble_reticulum/BLEInterface.py`
- live Python BLE behavior
- driver/platform code
- BlueZ/Bleak/DBus integration
- `RNS.Transport` integration
- ESP32 BLE integration
## Harness Design
The harness imports the real `BLEInterface` class, then binds these real Python methods onto a minimal fake object:
- `_handle_identity_handshake`
- `_check_duplicate_identity`
- `_compute_identity_hash`
- `_get_fragmenter_key`
The fake object supplies only the state those methods require:
- `address_to_identity`
- `identity_to_address`
- `address_to_interface`
- `spawned_interfaces`
- `peers`
- `fragmenters`
- `reassemblers`
- `_pending_identity_connections`
- `_pending_detach`
- `_last_real_data`
- `_zombie_timeout`
- fake driver
- fake fragmenter/reassembler constructors
- fake stale-address cleanup and spawn hooks
This avoids real RNS runtime, BlueZ, Bleak, DBus, and live BLE dependencies while still exercising the actual Python reference methods.
## Equivalence Cases Covered
| Case | Python reference behavior checked | C++ result checked |
|---|---|---|
| non-16-byte payload | returns `False` | `PassToReassembler`, `consumed=false` |
| new 16-byte identity | maps updated, fragmenter/reassembler created, pending removed, last-real-data updated, spawn requested | `AcceptedNewIdentity`, `CreateFragmentationState`, `MarkPeerReady`, `RemovePendingIdentity`, `MarkRealData` |
| known identity duplicate same | returns `True`, no normal data processing | `ConsumedDuplicateSameIdentity`, `consumed=true` |
| known identity duplicate mismatch | returns `True`, warning recorded | `ConsumedDuplicateMismatchedIdentity`, `Warn`, `consumed=true` |
| duplicate identity active elsewhere | disconnects current address | `RejectedDuplicateIdentity`, `DisconnectCurrentPeer` |
| duplicate identity with pending detach / stale old address | accepts new identity and invokes stale cleanup | `AcceptedNewIdentity`, `CleanupOldAddress`, `UpdatePeerAddress` |
| duplicate identity with zombie old connection | accepts new identity and disconnects old address | `AcceptedNewIdentity`, `DisconnectOldPeer`, `CleanupOldAddress` |
| MTU provided | fragmenter uses driver MTU | result MTU equals provided MTU |
| MTU missing | fragmenter falls back to 23 | result MTU equals 23 |
| pending identity removal | successful handshake removes pending address | `RemovePendingIdentity` |
| existing spawned interface path | existing peer address and `address_to_interface` update | `UpdatePeerAddress`, `MarkPeerReady` |
| exception compatibility | Python consumes packet after synthetic MTU exception | skipped for C++; manager has no platform exception surface |
The skipped exception case is intentional documentation: current Python consumes after adapter-side exceptions, but the C++ session manager does not call platform dependencies such as `driver.get_peer_mtu`, so `ErrorConsumed` is not exercised cleanly at Gate 2D.
## Verification
New Gate 2D test:
```sh
PYTHONPATH=migration/protocol_core pytest -q migration/tests/test_ble_peer_session_manager_python_equivalence.py
```
Result:
```text
11 passed, 1 skipped, 2 warnings in 0.24s
```
Gate 2C / Gate 2D regression:
```sh
PYTHONPATH=migration/protocol_core pytest -q migration/tests/test_ble_peer_session_manager_pybind.py migration/tests/test_ble_peer_session_manager_python_equivalence.py
```
Result:
```text
23 passed, 1 skipped, 2 warnings in 0.18s
```
Backend shim regression:
```sh
pytest -q migration/tests/test_fragmentation_backend_shim.py
```
Result:
```text
9 passed, 2 warnings in 0.64s
```
Migration regression set:
```sh
PYTHONPATH=migration/protocol_core pytest -q migration/tests/test_fragmentation_cpp_equivalence.py migration/tests/test_identity_helpers_cpp_equivalence.py migration/tests/test_ble_peer_session_manager_pybind.py migration/tests/test_ble_peer_session_manager_python_equivalence.py
```
Result:
```text
71 passed, 2 skipped, 2 warnings in 0.47s
```
## SQL
Companion SQL:
`migration/sql/mark_gate2d_protocol_session_python_equivalence_20260518_1611.sql`
The SQL marks `_handle_identity_handshake` as `PYTHON_EQUIVALENT` for phase
`2_ble_protocol_session_manager`, keeps tag `GLUE`, keeps `cpp_candidate=1`, and does not mark any field-accepted status.