Skip to content

Mark pending channel messages sent on RESP_CODE_SENT#186

Merged
wel97459 merged 4 commits into
zjs81:mainfrom
Specter242:feature/channel-ack-sent-status
Feb 21, 2026
Merged

Mark pending channel messages sent on RESP_CODE_SENT#186
wel97459 merged 4 commits into
zjs81:mainfrom
Specter242:feature/channel-ack-sent-status

Conversation

@Specter242

Copy link
Copy Markdown
Contributor

Problem

Outgoing channel messages can remain in a pending state even after the app receives RESP_CODE_SENT, especially in sparse/public-channel paths where echo timing is delayed.

Solution

  • On RESP_CODE_SENT, mark the most recent pending outgoing channel message as sent
  • Persist the status update in channel message storage
  • Preserve existing direct-message fallback behavior

Scope

  • lib/connector/meshcore_connector.dart only
  • No firmware protocol changes
  • No workspace/tooling/rules file changes

Validation

  • flutter analyze passes
  • flutter test passes

Closes #185

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d270683d25

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/connector/meshcore_connector.dart Outdated
if (_retryService != null) {
_retryService!.updateMessageFromSent(ackHash, timeoutMs);
}
_markMostRecentPendingChannelMessageSent();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restrict channel sent updates to channel ACKs

_handleMessageSent now calls _markMostRecentPendingChannelMessageSent() for every full RESP_CODE_SENT, but those responses are also used for direct messages. If a user has any pending outgoing channel message and then sends a direct message, the direct-message ACK will incorrectly flip that channel message to sent even though no channel send confirmation was received, producing false delivery state in the channel UI/storage.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Updated in 96fb9ca: channel pending→sent is now gated so it only runs when RESP_CODE_SENT was not matched to a direct message and there are no pending direct retries. This prevents direct-message ACKs from flipping channel state.

Comment thread lib/connector/meshcore_connector.dart Outdated
Comment on lines +2486 to +2487
if (_markMostRecentPendingChannelMessageSent()) {
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve direct fallback handling for short sent frames

In the legacy fallback path (frame.length < 10), returning immediately after marking a pending channel message means the previous direct-message fallback loop is skipped whenever any channel message is pending. On older firmware/protocol variants that emit short RESP_CODE_SENT frames, this leaves outgoing direct messages stuck in pending as long as a channel pending message exists.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 96fb9ca. I removed the early channel return from the short-frame fallback path; frame.length < 10 now preserves the original direct-message fallback loop so direct pending messages are still advanced on legacy short sent frames.

@Specter242

Copy link
Copy Markdown
Contributor Author
  1. 2.. 3... Hey, wait....

I need to switch to in progress as this is still not properly catching all acks.

@446564 446564 marked this pull request as draft February 19, 2026 01:34
@Specter242 Specter242 marked this pull request as ready for review February 21, 2026 18:31
@Specter242

Specter242 commented Feb 21, 2026

Copy link
Copy Markdown
Contributor Author

Update: fixed channel sent-state feedback for hardware that returns RESP_CODE_OK (code=0) instead of RESP_CODE_SENT (code=6) after channel sends.

What changed:

  • Added deterministic tracking for outgoing channel sends.
  • On RESP_CODE_SENT: direct hash match first, then queued channel pending->sent, then direct queue fallback.
  • Added RESP_CODE_OK fallback to promote queued outgoing channel message pending->sent for hardware/protocol paths that only emit OK.

Validation:

  • flutter analyze (touched files): clean
  • flutter test: pass
  • Manual on-device test with a T1000E tracker: Public channel sends now transition from clock (pending) to check (sent) when code=0 is received.

I will test with additional hardware soon and report any behavior differences.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e8e422f054

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/connector/meshcore_connector.dart Outdated
Comment on lines +2561 to +2562
final queuedMessageId = _pendingChannelCommandAckQueue.removeAt(0);
_markPendingChannelMessageSentById(queuedMessageId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Stop treating generic RESP_CODE_OK as a channel send ACK

_handleOk dequeues and marks a pending channel message as sent for every RESP_CODE_OK, but RESP_CODE_OK is a generic success code (see docs/BLE_PROTOCOL.md), not a channel-send-specific ACK. This means any unrelated OK response (for example, contact import/export flows that listen for OK in lib/screens/contacts_screen.dart) can incorrectly flip an unsent channel message to sent, and then the real send confirmation may advance the next queued message.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in f733129. RESP_CODE_OK no longer blindly dequeues channel state. sendFrame now tracks only commands that explicitly opt into generic ACK correlation, and channel pending->sent on OK happens only when the dequeued command is CMD_SEND_CHANNEL_TXT_MSG. Contacts import/export/zero-hop now opt in too, so their OK responses no longer advance channel send state.

Comment thread lib/connector/meshcore_connector.dart Outdated
Comment on lines +1330 to +1331
_pendingChannelSentQueue.add(message.messageId);
_pendingChannelCommandAckQueue.add(message.messageId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Queue reaction sends before consuming RESP_CODE_SENT

Only the non-reaction branch enqueues message IDs here, but reactions still send CMD_SEND_CHANNEL_TXT_MSG and can produce RESP_CODE_SENT. Because _handleMessageSent consumes one queued channel ID for unmatched sent responses, a sent response generated by a reaction can be applied to a different pending channel message, causing premature sent state in channel history.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in f733129. Reaction channel sends now enqueue a dedicated queue token before CMD_SEND_CHANNEL_TXT_MSG, and _markNextPendingChannelMessageSent consumes that token without promoting an unrelated pending message. This prevents reaction-generated RESP_CODE_SENT from being applied to another channel message.

@Specter242

Specter242 commented Feb 21, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up pushed in f733129 to address the latest review feedback:

  • correlate RESP_CODE_OK only to explicitly tracked command acks (channel send + contacts import/export/zero-hop operations)
  • queue reaction channel sends so RESP_CODE_SENT from reactions cannot advance a different pending channel message
  • keep channel send queue/ack state cleared on disconnect

darT analyze checks run on updated files: no issues.

@wel97459 wel97459 merged commit 2feff80 into zjs81:main Feb 21, 2026
6 checks passed
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.

Channel messages can remain pending after RESP_CODE_SENT

2 participants