Under USERPREFS_BLOCK_POSITION_ON_EVENT_CHANNEL every coordinate packet a
client aimed at the event channel was rejected with the "Location sharing is
disabled on this channel" notification - including the phone's own location
feed. Both apps hand a GPS-less node its fix as a POSITION_APP packet
addressed to the node itself on channel 0; that packet never leaves the
device (Router::sendLocal delivers it locally) but resolved to the event
channel and was dropped before PositionModule saw it. Result: the toast on
every location tick, and nodes without a GPS never learned a position to
share on their private channel.
Position traffic now converges on the position channel - findPositionChannel(),
the first channel with non-zero on-wire precision, which is never the event
channel:
- From-us-to-us coordinate packets are exempt from the event block.
- Local coordinate sends aimed at the event channel (phone share-location,
request-position, waypoints, any module/UI originator) are moved onto the
position channel in Router::sendLocal and PhoneAPI instead of rejected. The
client notification is only sent when no channel carries positions at all.
- A position request DM'd to us on the event channel is answered on the
position channel at that channel's precision (request_id preserved, same
reply throttle); the requester's coordinates are still not stored,
forwarded, relayed or published. want_response from the bitfield is merged
before the event-channel decode short-circuit so such requests are seen.
- PositionModule::sendOurPosition, positionUnchangedSinceLastSend and
MeshService::trySendPosition use the shared helper instead of three copies
of the same walk.
Non-event builds are unaffected: the coercion compiles out and the helper
matches the previous walk.
Tests: coverage-event-policy (test_event_channel_phone_api,
test_event_channel_router, test_position_precision, test_mqtt,
test_nexthop_routing) and the same suites with the policy off.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>