Multi-hotspot SYSTEM inject must not REPEAT or bridge-downlink TGs to peers
whose RPTO OPTIONS omit the call TG. Exempt parrot/echo 9990–9999 for the
RX_PEER that keyed the service TG.
Add real-stack REPEAT and proxy fan-in E2E tests so regressions outside
DeterministicScenario are caught. Remove duplicate or fragile tests,
consolidate monitor remap cases, and document harness vs integration policy.
Overlay Talker Alias in repeated DMRD bursts so WPSD/MMDVMHost can display
aliases on RX, buffer TA from OBP voice, and inject the template at VHEAD
when the source sends no TA.
Match bridge_tables_with_active_source and to_target forward selection on
subscription rows; add parity tests vs legacy BRIDGES scan including OBP dedup.
Add opt-in REPORTS.MQTT with retained shared state and live voice_event
topics, topology static TG in v2 payloads, dashboard_state builder, and
SIGHUP reload.
Decouple bridge events from TCP send via a reactor-drained queue (50ms, 2048
events). Export peer connected_at in topology so monitor timers survive refresh.
SessionReplayer replays golden fixtures through DeterministicScenario;
add HBP group voice session, behavior tests, and dev CAPTURE scaffold.
Set pytest pythonpath so bare `pytest` finds tests.* imports.
Move Talker Alias / embedded LC and BRIDGES table lifecycle into
application/bridge/; BridgeUseCases remains the public facade with
dmrd_received and unit/private paths only.
Move shared TG/OBP helpers and legacy timer loops (rule_timer, trimmers,
bridge_reset, bridge_debug) into application/bridge/; BridgeUseCases keeps
the public facade via BridgeTimerMixin.
Introduce RuntimeContextHolder with ConfigProxy so main wiring keeps a stable
config view while SIGHUP reload builds a deep copy, applies reload_server_config,
then swaps the pointer only on success.
Inject ReportingUseCases into BridgeUseCases and centralize BRDG_EVENT
emission through _send_bridge_event; use reporting use cases for periodic
CONFIG/BRIDGE snapshots in main.
Stop renumbering DMRD sequence to 1..255 on replay; duplicate seq values
after ~15–30s caused MMDVMHost to drop voice while TX continued. Match
legacy playback.py (stream ID rewrite only).
Add TALKER_ALIAS_TEXT_FORMAT: single or comma-separated encodings for
embedded LC (e.g. utf8,iso8 for Motorola and Hytera). Example template
defaults to both formats; runtime default remains utf8 when omitted.
Extract corrected encode_emblc and TA embedded-LC wiring from domain into
infrastructure adapters. Inject DmrEmbeddedLcEncoder and TalkerAliasEmblcEncoder
from main.py so application layers stay free of infrastructure imports. Use the
fixed encoder for bridge group LC and pkt_gen as well as Talker Alias overlay.
- both: passthrough when source sends TA (DMRA or embedded voice), inject
template otherwise; OBP sources inject immediately at VHEAD
- Always rewrite destination group embedded LC on bridge forward (legacy
parity; fixes OBP TG mismatch packet loss introduced by TA branch)
- Fix dmr_utils3 encode_emblc index bug for lossless injected TA text
- Log decoded TA from voice; strict MMDVM DMRA wire layout
- chore: ruff per-file E402 ignore for main/parrot entrypoints
Popping STATUS[stream_id] on BCSQ (and forward-leg END,TX) destroyed live
stream state mid-call, causing repeated *CALL START* churn, a BCSQ storm and
GROUP_HANGTIME ping-pong on HBP masters that left receivers (MMDVMHost) with
only the voice header before the watchdog expired. Legacy hblink only records
_bcsq[tgid] and skips the quenched target; the stream entry survives until the
trimmer removes it by age. Emit a one-shot monitor END,TX and keep STATUS.
Clear stale OpenBridge TX chips in the monitor when BCSQ quenches a forward
leg or the source stream goes idle, using the same BRDG_EVENT format as legacy.