fix(messaging): wait for shared-contact routing ACK - #6603
Conversation
📝 WalkthroughWalkthrough
ChangesStrict routing acknowledgement await
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant PacketHandlerImpl
participant Radio
participant MeshDataHandlerImpl
Caller->>PacketHandlerImpl: sendToRadioAndAwait(packet)
PacketHandlerImpl->>Radio: enqueue and send packet
Radio-->>PacketHandlerImpl: queue status
PacketHandlerImpl-->>Caller: continue waiting for routing result
Radio-->>MeshDataHandlerImpl: routing ACK or NAK
MeshDataHandlerImpl->>PacketHandlerImpl: complete response
PacketHandlerImpl-->>Caller: true for ACK, false for NAK
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@core/data/src/commonMain/kotlin/org/meshtastic/core/data/manager/PacketHandlerImpl.kt`:
- Around line 192-196: Update the requestId == 0 fallback in PacketHandlerImpl
so it selects the first incomplete queue response, completes it, and uses that
entry’s packet ID to find and complete the corresponding routing response when
required. If no queue response exists, leave routingResponse untouched rather
than completing an unrelated pending entry.
In
`@core/data/src/commonTest/kotlin/org/meshtastic/core/data/manager/PacketHandlerImplTest.kt`:
- Around line 205-217: The test strict await succeeds on routing ack must verify
it remains incomplete after queue acceptance. In strict await succeeds on
routing ack, add an assertFalse(result.isCompleted) immediately after
handleQueueStatus and testScheduler.runCurrent(), before
handler.removeResponse(794, complete = true), then retain the final success
assertion.
In
`@core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/CommandSender.kt`:
- Around line 59-64: Update the sendAdminAwait documentation in
core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/CommandSender.kt:59-64
and sendToRadioAndAwait documentation in
core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/PacketHandler.kt:32-38
to document every strict-await outcome: return true for routing ACKs and
synchronous local-loopback delivery via ERRNO_SHOULD_RELEASE, and return false
for disconnection, transport-send failure, routing NAKs, queue rejection, and
timeout.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: e76ac883-b5b7-4f65-b5f3-4df48ce87855
📒 Files selected for processing (6)
core/data/src/commonMain/kotlin/org/meshtastic/core/data/manager/MeshDataHandlerImpl.ktcore/data/src/commonMain/kotlin/org/meshtastic/core/data/manager/PacketHandlerImpl.ktcore/data/src/commonTest/kotlin/org/meshtastic/core/data/manager/MeshDataHandlerTest.ktcore/data/src/commonTest/kotlin/org/meshtastic/core/data/manager/PacketHandlerImplTest.ktcore/repository/src/commonMain/kotlin/org/meshtastic/core/repository/CommandSender.ktcore/repository/src/commonMain/kotlin/org/meshtastic/core/repository/PacketHandler.kt
jamesarich
left a comment
There was a problem hiding this comment.
Nice fix — the queue/routing phase split is the right mechanism, and the test matrix (queue-acceptance-doesn't-complete, ACK, NAK, disconnected, transport-throw, zero-ID) is exactly what this path needs. Merging as-is; two asks for the record and one follow-up:
-
Please add the two semantic changes to the description: (a)
sendToRadioAndAwaitnow fails fast when disconnected instead of leaving the packet queued for post-reconnect transmission; (b) a routing NAK arriving before itsQueueStatusnow releases the queue deferred as failure. Both look right, but they're behavior changes on a shared path and should be discoverable from the PR record. -
Resolving the CodeRabbit threads as non-blocking, with rationale: the zero-ID fallback correlation issue (queue and routing responses picked independently, potentially from different packets) is real but confined to the rare
requestId == 0fallback, and the strict routing path currently has a single production caller — the pre-existing ambiguity there predates this PR. Worth a follow-up fix (correlate both maps through the same selected entry), as is the suggestedassertFalse(result.isCompleted)mid-test assertion and the KDoc on strict-await outcomes. -
Heads-up: #6598 rewrites these same admission seams and will rebase over this — its typed-outcome machinery may eventually subsume the two-deferred split.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Model each awaited packet as a single pending owner with distinct transport-queue and routing stages. Start the response window only after an active transport admits the frame, reserve packet IDs until every required terminal stage completes, correlate zero-ID queue status only with dispatched queue waiters, and preserve strict routing ACK/NAK semantics from meshtastic#6603. Persist terminal outcomes from the same ownership state so stop, rejection, timeout, and routing failure cannot be mistaken for successful queue admission.
Summary
Bug fixes
sendAdminAwait.QueueStatus(res = 0)from releasing the first PKI DM before the localadd_contactpacket is processed.QueueStatus, fail both deferred phases so the packet-queue worker is released.Root cause
This is a residual sequencing path from #4988 and a follow-up to #4992 and #5005.
#4992 made shared-contact installation suspending, but
sendToRadioAndAwaitused the same deferred that the packet-queue worker uses forQueueStatus.QueueStatus(res = 0)reports that firmware accepted or queued the packet; it is not the later routing acknowledgement. On firmware 2.7.20, a self-addressed packet is queued for local processing and QueueStatus is returned beforeAdminModuleruns. That allowedSendMessageUseCaseto enqueue the dependent PKI DM beforeadd_contactreached the firmware NodeDB.The fix tracks those two phases separately. QueueStatus continues to release the transport queue worker, while the strict caller remains suspended until the correlated routing ACK/NAK arrives. A queue or local transport failure still fails both phases, and the existing synchronous
ERRNO_SHOULD_RELEASEsuccess remains supported.This intentionally changes two shared-path behaviors:
sendToRadioAndAwaitnow returns failure immediately while disconnected rather than leaving the packet queued for post-reconnect transmission, and a routing NAK received before itsQueueStatusalso fails the queue deferred so queue processing cannot remain blocked.Firmware registers
RoutingModulelast, afterAdminModule; for a valid shared contact,NodeDB::addFromContactcompletes before the routing ACK is generated. This makes that ACK a processing barrier for this path without changing the wire protocol.Relevant protocol and firmware paths:
add_contacthandling: https://github.com/meshtastic/firmware/blob/v2.7.20.6658ec2/src/modules/AdminModule.cpp#L355-L363Related work
Testing Performed
:core:data:testAndroidHostTest— 464/464 after the review follow-up.:core:repository:testAndroidHostTest— 21/21.PacketHandlerImplTest— 15/15, including zero-ID response correlation.:core:data:spotlessCheck :core:repository:spotlessCheck:core:data:detekt :core:repository:detektkmpSmokeCompileLimitations
A missing routing ACK is not proof that firmware failed to install the contact, so the existing caller remains best-effort after a NAK or timeout and still enqueues the DM. This PR fixes the deterministic queue-admission ordering race; it does not change message failure UX or retry policy.