Replace internal bridge terminology with routing (RoutingUseCases, AclRouter,
routing_table export). SubscriptionStore remains runtime authority with O(1)
indexes for router and downlink filters. Fix STATIC TG parity on OPTIONS/RPTO,
parrot in-band edge cases, and remove per-packet routing_table export from the
hot path that caused high CPU under multi-hotspot OBP load.
`main.py` wires configuration, **LoopingCall** timers, factories for **HBPProtocol**, report client, and injects use cases.
## Runtime routing authority
Voice routing is driven by **`SubscriptionStore`** (domain subscriptions). `RoutingUseCases` orchestrates `dmrd_received` and delegates forward resolution to **`SubscriptionRouter`**.
- **`InMemoryAclRouter`** (`AclRouter` port) — ACL range checks only (`acl_check`).
- **`routing_table_for_report()`** — export shim for monitor/report (legacy BRIDGE_SND shape); not used for runtime forwards.
Wire opcodes and YAML keys may still say “bridge” for legacy monitor compatibility (`BRIDGE_SND`, `GEN_STAT_BRIDGES`).
Regression tests live under **`tests/`**, **one topic per file**, grouped by domain (`bridge/`, `hbp/`, `obp/`, …). Full file index: `tests/README.md` (repo root, maintainer checkout).
Regression tests live under **`tests/`**, **one topic per file**, grouped by domain (`routing/`, `hbp/`, `obp/`, …). Full file index: `tests/README.md` (repo root, maintainer checkout).
They use an in-process **deterministic harness** (no Twisted reactor, no UDP sockets).
@ -13,7 +13,7 @@ On the wire, extended OpenBridge uses the **`DMRE`** opcode. The **embedded prot
- **`DMRD`** version 1 — HMAC-SHA1 authenticated payload (compatibility mode); or
- **`DMRE`** — extended frame with **BLAKE2b** MAC, embedded version, timestamps, **hops**, source server/repeater IDs, etc. (**DMRE v5** = embedded version 5, recommended above).
This stack implements the **OPENBRIDGE** peer mode in **`udp_hbp.py`** and bridge routing in **`BridgeUseCases`**.
This stack implements the **OPENBRIDGE** peer mode in **`udp_hbp.py`** and voice routing in **`RoutingUseCases`** (`application/routing/`, `application/subscription/`).
Private handling uses CSBK/data/unit branches, `SUB_MAP` lookup, and busy-slot checks where applicable (see `BridgeUseCases` in source).
Private handling uses CSBK/data/unit branches, `SUB_MAP` lookup, and busy-slot checks where applicable (see `RoutingUseCases` in source).
## TG / ID 4000 (unit)
@ -21,4 +21,4 @@ As documented in [Special numbers](special-numbers.md), a **private** call to **
Private **START/END** events may be emitted to the report TCP client when **`REPORTS.REPORT`** is enabled, analogous to group voice (shape `PRIVATE VOICE,...` where implemented).
For protocol ingress details, see [HBP](../protocols/hbp.md) and the bridge use cases in source (`BridgeUseCases._pvt_call_received`).
For protocol ingress details, see [HBP](../protocols/hbp.md) and the routing use cases in source (`RoutingUseCases._pvt_call_received`).
1. **Dominio** (`src/adn_server/domain/`) — entidades, objetos de valor, errores, `Result`. Sin E/S, sin Twisted.
2. **Aplicación** (`src/adn_server/application/`) — casos de uso (`BridgeUseCases`, `VoiceUseCases`, …) y **ports** (interfaces).
2. **Aplicación** (`src/adn_server/application/`) — casos de uso (`RoutingUseCases`, `VoiceUseCases`, …) y **ports** (interfaces).
3. **Infraestructura** (`src/adn_server/infrastructure/`) — config YAML, Twisted UDP/TCP, voz, persistencia, adaptadores de seguridad.
**Regla de dependencias:** infraestructura → aplicación → dominio (solo hacia dentro).
@ -12,13 +12,23 @@
`main.py` cablea configuración, temporizadores **LoopingCall**, fábricas para **HBPProtocol**, servidor de informes e inyecta casos de uso.
## Autoridad de enrutado en runtime
El enrutado de voz lo gobierna **`SubscriptionStore`** (suscripciones de dominio). `RoutingUseCases` orquesta `dmrd_received` y delega la resolución de reenvío a **`SubscriptionRouter`**.
- **`InMemoryAclRouter`** (port `AclRouter`) — solo comprobaciones ACL (`acl_check`).
- **`routing_table_for_report()`** — shim de exportación para monitor/informes (forma legacy BRIDGE_SND); no se usa para reenvíos en runtime.
Los opcodes wire y claves YAML pueden seguir diciendo “bridge” por compatibilidad con el monitor legacy (`BRIDGE_SND`, `GEN_STAT_BRIDGES`).
## Dónde leer código
| Tema | Ubicación |
|------|-----------|
| Enrutado de bridge, `dmrd_received`, bucle OpenBridge | `application/bridge_use_cases.py` |
| Enrutado de voz, `dmrd_received`, reenvío OpenBridge | `application/routing_use_cases.py`, `application/routing/` |
| Store de suscripciones, router, reglas in-band | `application/subscription/` |
@ -13,7 +13,7 @@ En cable, OpenBridge extendido usa el opcode **`DMRE`**. El **byte de versión d
- **`DMRD`** versión 1 — carga autenticada HMAC-SHA1 (modo de compatibilidad); o
- **`DMRE`** — trama extendida con MAC **BLAKE2b**, versión embebida, marcas de tiempo, **saltos**, IDs servidor/repetidor de origen, etc. (**DMRE v5** = versión embebida 5, recomendada arriba).
Esta pila implementa el modo par **OPENBRIDGE** en **`udp_hbp.py`** y el enrutado de bridges en **`BridgeUseCases`**.
Esta pila implementa el modo par **OPENBRIDGE** en **`udp_hbp.py`** y el enrutado de voz en **`RoutingUseCases`** (`application/routing/`, `application/subscription/`).
@ -11,7 +11,7 @@ Las llamadas **unitarias (privadas)** usan un camino distinto a la voz de **grup
## OpenBridge frente a MASTER
El manejo privado usa ramas CSBK/datos/unit, búsqueda `SUB_MAP` y comprobaciones de slot ocupado donde aplique (ver `BridgeUseCases` en el código).
El manejo privado usa ramas CSBK/datos/unit, búsqueda `SUB_MAP` y comprobaciones de slot ocupado donde aplique (ver `RoutingUseCases` en el código).
## TG / ID 4000 (unitaria)
@ -21,4 +21,4 @@ Como en [Números especiales](special-numbers.md), una llamada **privada** a **4
Los eventos privados **START/END** pueden emitirse al cliente TCP de informes si **`REPORTS.REPORT`** está habilitado, análogo a voz de grupo (forma `PRIVATE VOICE,...` donde esté implementado).
Para detalles de ingreso de protocolo, ver [HBP](../protocols/hbp.md) y los casos de uso de bridge en código (`BridgeUseCases._pvt_call_received`).
Para detalles de ingreso de protocolo, ver [HBP](../protocols/hbp.md) y los casos de uso de routing en código (`RoutingUseCases._pvt_call_received`).
| `support/` | Shared stacks (`hbp_repeat_stack`, monitor sim) — not run as tests |
| `harness/` | Shared fakes (`DeterministicScenario`, assertions) — not run as tests |
## Integration vs harness
Most bridge/voice tests inject packets via **`DeterministicScenario`** (`bridge.dmrd_received` on fakes). That is fast but **skips**`udp_hbp` REPEAT rewrite and proxy UDP fan-in.
Most routing/voice tests inject packets via **`DeterministicScenario`** (`routing.dmrd_received` on fakes). That is fast but **skips**`udp_hbp` REPEAT rewrite and proxy UDP fan-in.
For regressions on those paths, use:
@ -48,17 +48,19 @@ Mark new stack tests with `@pytest.mark.integration`.
## Files by domain
### bridge/
### routing/
| File | Tests | Topic |
|------|-------|-------|
| `test_config_reload.py` | 1 | Merge system config on reload |