* fix: inject-only slot contention, monitor events, and UA timer display
Per-peer slot contention for inject-only multi-hotspot: REPEAT and bridge
downlink respect each hotspot's busy slot instead of blocking the whole
MASTER. REPEAT monitor reports and companion TX fan-out are filtered when
the target peer would not accept the downlink.
Monitor topology remap reads MASTER STATUS via bootstrap callback and
suppresses OBP/companion voice events for peers with an active QSO on
another TG in the same slot. START,RX is emitted only on a new stream id.
UA TIMER=0 (legacy no-expiry): domain sentinel, topology omits infinite
ua_timer_min, SINGLE sessions store expires=0 instead of ~68-year offsets,
and export omits absurd expires_at values.
* feat: dynamic TG restore, OBP cross-slot downlink, and DB migration 005
- Export ua_multi_tgs in topology for monitor chip restore after server restart
- Defer OBP→HBP slot contention on inject-only proxies; clear other-slot SINGLE session on new TX
- Fix infinite UA timer persistence (expires_at NULL) and restore from DB (expires_at=0 sentinel)
- Push CONFIG to monitor after async dynamic-TG restore on RPTC
- Migration 005_peer_dynamic_tgs_expires_null (shared with adn-monitor)
Validate TS1/TS2 static tokens as numeric TG ids so comma-separated
garbage (e.g. TS2=730444,VOICE=0) is ignored in topology, downlink,
and static bridge refresh.
Block concurrent group voice on the same slot during active QSO; apply
GROUP_HANGTIME only after VTERM. Derive simplex/duplex from RPTC, force
simplex downlink to TS2, export rf_mode in topology, and drop duplicate
static TGs from TS2 when TS1 already lists them.
* chore(ci): sync develop via merge instead of force-push
Merge master into develop after release so local checkouts can git pull
without reset --hard. Try fast-forward first; merge commit after squash releases.
* fix: restore cross-slot downlink and REPEAT monitor activity
Cross-slot TG downlink, DMRA index parity, and REPEAT monitor START/TX reporting.
* fix: remap REPEAT DMRD slot to peer OPTIONS for cross-slot downlink (#17)
Flip the DMRD timeslot bit per receiver so hotspots hear group voice on
the TS where the TG is configured (static OPTIONS or dynamic UA), and
emit inject-proxy BRDG field 7 on that same slot for monitor TE parity.
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat: persist peer dynamic TGs in MariaDB across reconnects
Add DATABASE config, async DynamicTgStore, and restore on RPTC so
SINGLE=0/1 dynamics survive hotspot disconnects and server restarts
without blocking the DMRD voice path.
* fix: ensure peer_dynamic_tgs table on server startup
Apply migration 004 idempotently at boot so the server does not depend
on adn-monitor db_bootstrap when peer_dynamic_tgs is missing.
* fix: import DynamicTgEntry for ruff F821 in subscription_table
* fix: log clear MariaDB startup failures to file and stderr
Validate DATABASE at config load and on connect; map common MySQL
errors to actionable messages so the server does not fail silently.
* fix: TG 4000 clears STATUS and bridge legs after dynamic reset
Clear RX slot state to stop RPTO re-seeding cleared sessions, run
in-band 4000 deactivation on inject-only paths, and mark downlink dirty.
* fix: complete TG 4000 reset for monitor and dynamic TG persistence
Emit INGRESS BRDG_EVENT so SINGLE=0 UA chips clear without stuck TX;
wipe all peer dynamic rows from memory and MariaDB on reset. Never store
TG 4000 as a UA session. Require DATABASE only for full peer-server configs.
When voice arrives on TS2 but the hotspot lists the TG on TS1 (or vice
versa), flip the slot bit on send_peer so duplex radios RX on the
configured timeslot.
Normalize all Python sources to the standard ADN copyright block with
complete GPLv3 notice. Add legacy attribution on routing and dmr_utils
ports; drop SemVer wording from changelog and fix an unused test import.
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.
Require subscription_store in BridgeUseCases and route timer, OPTIONS,
static TG, and OBP mutations through store ops with export-only BRIDGES shim.
Fix dashboard YAML static TG fallback and sole-hotspot monitor remap for
dynamic UA when a bridge leg is active.
Move stat_trimmer, bridge_debug, bridge_reset, bridge_table (static TG,
reflectors, UA), and OBP source ensure to mutate SubscriptionStore first
and export to the BRIDGES shim; batch OPTIONS loops export once at the end.
Add InbandTriggers to Subscription with ON/OFF/RESET import/export parity.
apply_in_band_signalling mutates the store directly and exports to the
BRIDGES shim (SINGLE_MODE, TG 4000, reflector # rules unchanged).
Mutate SubscriptionStore in rule_timer_loop and export to the BRIDGES shim
without re-importing stale router state. Voice forward uses resolved ForwardLeg
list instead of scanning dict rows when the store is wired.
Subscription store and router are always active when wired at bootstrap;
drop YAML toggles and flag-off test paths. Sync router into store before
get_bridges() export and after make_static_tg mutations.
Sync subscription store after timer and in-band mutations, add optional
store authority with BRIDGES export shim, wire MeshCodecRegistry into
OBP udp_hbp paths, and extend harness parity tests.
Push STATE_SND when peers send RPTO so monitor chips update without reload.
Fetch and inject MySQL OPTIONS immediately on PASS= instead of a 10s delay.
Track per-peer dynamic TG sets for SINGLE=0 so keyed hotspots hear each other.
Enforce strict SINGLE=1 RX exclusivity, always filter inject-only downlink by
each peer's own OPTIONS, and push self-service DB options only after PASS=.
Stop merged SYSTEM static TG lists from leaking across hotspots in topology.
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.
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.
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.