- The state a prompt shares between its thread and the reactor is a
small dataclass (_PromptRun) instead of a dict with string keys.
- "Is the slot held by another stream?" now lives in routing/helpers.py
next to slot_has_active_voice, and both read the RX/TX legs through
one helper, instead of a third copy of that check in voice_use_cases.
- Blank lines and the test header follow the rest of the repo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Voice ident, the 9991-9999 on-demand files and the disconnected prompt
run on a worker thread and sent every frame through send_voice_packet,
which refreshes TX_TIME but never TX_TYPE. The slot stayed at VTERM for
the whole prompt, so routing saw it free: on a system with
GROUP_HANGTIME 0 routed group voice went out as a second stream on the
same slot, and a radio keying up did not stop the prompt either.
Scheduled and TTS broadcasts already get this right. The three prompts
now share play_on_slot: the thread only paces the frames, and each one
is sent on the reactor, which marks the slot the way broadcasts do
(TX_TYPE=VHEAD, TX_STREAM_ID, TX_RFS), stops the prompt when a radio is
talking or another stream holds the slot, and frees it at the end if
the prompt still holds it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Route announcements/TTS through synthetic PTT on the proxy MASTER (SERVER_ID
peer, normal dmrd_received forwarding). Emit START/END TX report events for
inject so monitor fans out to SYSTEM-N; configurable server voice DMR_ID.
* fix: audit wave 1 server hygiene refactors
Inject call_later into PlaybackUseCases, move voice config mtime watch to
bootstrap, complete SubscriptionStore port methods, and relocate echo
routing seed to the application layer.
* fix: document dashboard_state in report-v2 schema
Add dashboard_state to report-v2.json with a two-master example fixture,
update public protocol docs for HELLO → STATE_SND connect flow, and drop
the unused TOPOLOGY_JSON HELLO feature token.
* fix: add ReportWire contract tests against report-v2 schema
Assert state_frames and bridge_event_frames output validates against
committed example fixtures and the report-v2 JSON schema.
Fix test imports for echo_seed module relocation.
* fix: align OPTIONS static validity checks across routing and report
Delegate subscription_table validation to peer_options_static_valid so empty
OPTIONS is valid and PASS-mixed strings are rejected consistently.
* fix: OBP DMRE source-server validation without ALLOW_UNREG_ID bypass
Port OPENBRIDGE.validate_id lookup for 6-7 digit source servers so OBP
ingress matches legacy production config (VALIDATE_SERVER_IDS=True).
* fix: audit items 11-13 coverage, infra tests, and warning logs
* fix: add tests/fakes shim for application test decoupling
* fix: per-stream OBP bridge TX legs for concurrent MASTER downlink
When two OBP voice streams share the same MASTER timeslot, stop
flip-flopping the flat TX row so per-peer downlink gates stay stable.
* fix: ruff lint in OBP concurrent streams downlink test
Remove dead code after return and unused start_tx_events variable.
Drop duplicate bridge/parrot modules and develop-only slot contention tests
that do not match the subscription routing harness on trial/downlink-clean.
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.
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.