Skip to content

fix(meshcore): cross-feeder channel_text dedup (#387)#389

Merged
pskillen merged 5 commits into
mainfrom
api-387/pskillen/mc-cross-feeder-dedup
Jun 2, 2026
Merged

fix(meshcore): cross-feeder channel_text dedup (#387)#389
pskillen merged 5 commits into
mainfrom
api-387/pskillen/mc-cross-feeder-dedup

Conversation

@pskillen
Copy link
Copy Markdown
Owner

@pskillen pskillen commented Jun 2, 2026

Summary

Implements cross-feeder dedup for MeshCore channel_text ingest (#387).

When two feeders hear the same on-air channel post (no wire pkt_hash on channel_message), the API now creates one MeshCoreTextPacket, N MeshCorePacketObservation rows, and one TextMessage — matching Meshtastic multi-feeder behaviour. Heard API returns all feeders (len(heard) == 2).

Dedup key resolution (dedup_key.py):

  1. Wire pkt_hash when present (e.g. rx_log_data, future TEXT_MSG upload per #385).
  2. channel_text: content hash over constellation + canonical MessageChannel.id + sender_timestamp + stripped text.
  3. Fallback: envelope surrogate hash (advert, contact, raw).

Fix: ingest now persists the resolved key on MeshCoreRawPacket.pkt_hash (previously lookup used a surrogate but create stored null).

No DB migration; historical duplicate TextMessage rows are not backfilled. No bot changes required for MVP.

Land this before or rebase #386 (path twin) if both are open.

Closes #387

Testing performed

  • python -m pytest Meshflow/meshcore_packets/tests/test_dedup_key.py Meshflow/meshcore_packets/tests/test_cross_feeder_dedup.py Meshflow/meshcore_packets/tests/test_ingest.py Meshflow/meshcore_packets/tests/test_canonical_channels.py -v
  • Updated ADR-0004 (partial), meshcore.md, text-message-channels.md, phase-3-outstanding.md

Post-deploy (pre-prod)

  1. One channel ping heard by two feeders.
  2. SQL: one TextMessage, obs_count >= 2, non-null pkt_hash on new ingests.
  3. UI Messages (MC): single row, Heard shows 2.

Centralize wire pkt_hash, channel_text content hash, and envelope
surrogate fallback for cross-feeder dedup (#387).
Resolve channel before lookup, store computed or wire key in pkt_hash,
and match duplicates via dedup_key (#387).
HTTP ingest from two feeders yields one packet, two observations,
one TextMessage, and heard length 2 (#387).
Document content-hash keys, cross-feeder behaviour, and #387 tracking.
@pskillen-nes pskillen-nes force-pushed the api-387/pskillen/mc-cross-feeder-dedup branch from 9eb2014 to 8a80c25 Compare June 2, 2026 14:47
Surrogate and content hashes used the full 64-bit digest, which overflows
Postgres BIGINT on advert/raw ingest. Share digest_to_signed_bigint across
dedup paths (#387).
@pskillen pskillen merged commit 8d32180 into main Jun 2, 2026
6 checks passed
@pskillen pskillen deleted the api-387/pskillen/mc-cross-feeder-dedup branch June 2, 2026 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MeshCore P3] Cross-feeder dedup — one on-air channel message → one packet + N observations (not N TextMessages)

2 participants