Skip to content

Align Base UI message status wording#10921

Draft
RCGV1 wants to merge 12 commits into
meshtastic:developfrom
RCGV1:codex/base-ui-message-status
Draft

Align Base UI message status wording#10921
RCGV1 wants to merge 12 commits into
meshtastic:developfrom
RCGV1:codex/base-ui-message-status

Conversation

@RCGV1

@RCGV1 RCGV1 commented Jul 7, 2026

Copy link
Copy Markdown
Member

Source issues

Summary

  • Align Base UI message-status text with the source-of-truth design issue wording.
  • Map current firmware routing errors to distinct user-facing Base UI statuses, including admin, rate-limit, interface, app-response, authorization, and PKI key states.
  • Keep untrackable phone-originated sends from showing false pending text; only want_ack DMs are tracked for routing status updates.
  • Make the notification banner renderer C++17-compliant for native builds by replacing initialized VLAs with standard storage.

UI validation

Local Base UI status and banner captures were generated and reviewed. Evidence image is embedded below from an evidence-only branch; screenshot files are intentionally not committed to this PR branch.

Firmware Base UI message status contact sheet

Validation

  • trunk fmt / commit hook passed.
  • git diff --check passed.
  • PLATFORMIO_BUILD_FLAGS='-DMESHTASTIC_INCLUDE_BASE_UI_MESSAGE_STATUS' ~/.platformio/penv/bin/python -m platformio test -e native-macos -f test_message_status_text passed: 18 test cases.
  • ~/.platformio/penv/bin/python -m platformio run -e native-macos passed.

Hardware verification

Not yet performed. This PR is draft until Base UI hardware verification is complete.

Local notes

  • ./bin/run-tests.sh -f test_message_status_text could not run directly on this macOS host because the wrapper requires GNU bash/mapfile and GNU find -printf.
  • ./bin/test-native-docker.sh -f test_message_status_text could not run because the Docker daemon was not available locally.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds shared message-status tracking and rendering across message storage, routing, UI, and test coverage, updates notification rendering buffers to vector-backed storage, and extends size-script manifest discovery and fallback behavior.

Changes

Message delivery status tracking and rendering

Layer / File(s) Summary
Ack status model
src/MessageStore.h, src/MessageStore.cpp
Expands AckStatus, extends StoredMessage with tracking fields, broadens compile guards, and adds routing/status mapping plus update APIs.
MessageStore ack tracking
src/MessageStore.cpp
addFromPacket and addFromString record tracking metadata, and the new update methods revise the newest matching tracked message.
Shared status text helpers
src/graphics/draw/MessageStatusText.h, src/graphics/draw/MessageStatusText.cpp
Adds inline and banner status text helpers and failure-state classification for StoredMessage ack state.
MessageRenderer status lines
src/graphics/draw/MessageRenderer.cpp
Adds inline status-line caching and rendering, plus expanded failure-mark handling and broadcast checks.
Ack flow wiring
src/modules/CannedMessageModule.cpp, src/modules/RoutingModule.cpp, src/mesh/MeshService.cpp
Routes outgoing messages, routing responses, banner text generation, and phone-delivered history through the new status path.
Tests and evidence
test/test_message_status_text/test_main.cpp, artifacts/base-ui-message-status/README.md, test/native-suite-count
Adds status-text and ack-tracking tests, updates the native suite count, and documents screenshot evidence.

NotificationRenderer buffer refactor

Layer / File(s) Summary
Vector-backed notification buffers
src/graphics/draw/NotificationRenderer.cpp
Replaces stack arrays and VLAs with std::vector and std::array storage and updates rendering call sites to use contiguous buffers.

Build size script recursion and fallback

Layer / File(s) Summary
Manifest discovery and flash fallback
bin/collect_sizes.py
Recurses through manifest subdirectories, sorts discovered manifests, and falls back to OTA zip bytes when no .bin size is present.
Size script tests
bin/test_size_scripts.py
Adds coverage for OTA-only size collection and recursive manifest discovery.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

Poem

A bunny hops through ack and glow,
“Sending...” now tells what we know.
A banner, line, and tiny mark,
Make message paths less dim and dark.
🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main change: aligning Base UI message-status wording.
Description check ✅ Passed The description covers issues, summary, validation, and hardware status; only the template's attestation checklist is omitted.

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

⚡ Try this PR in the Web Flasher

Flash this PR in the Web Flasher

firmware commit boards expires

Warning

This is an automated, unreviewed CI test build. Back up your device configuration
before flashing, and only flash devices you are able to recover.

Supported boards built by this PR (27)
Device Board Platform
Crowpanel Adv 3.5 TFT elecrow-adv-35-tft esp32-s3
Heltec HT62 heltec-ht62-esp32c3-sx1262 esp32-c3
Heltec Mesh Node 096 heltec-mesh-node-t096 nrf52840
Heltec Mesh Node T1 heltec-mesh-node-t1 nrf52840
Heltec Mesh Node T114 heltec-mesh-node-t114 nrf52840
Heltec V3 heltec-v3 esp32-s3
Heltec V4 heltec-v4 esp32-s3
Meshnology W10 meshnology_w10 esp32-s3
Raspberry Pi Pico pico rp2040
Raspberry Pi Pico W picow rp2040
RAK WisMesh Tag rak_wismeshtag nrf52840
RAK WisBlock 11200 rak11200 esp32
RAK WisBlock 11310 rak11310 rp2040
RAK3312 rak3312 esp32-s3
RAK WisBlock 4631 rak4631 nrf52840
Seeed SenseCAP Mesh-Tracker-X1 seeed_mesh_tracker_X1 nrf52840
Seeed Wio Tracker L1 seeed_wio_tracker_L1 nrf52840
Seeed Xiao NRF52840 Kit seeed_xiao_nrf52840_kit nrf52840
Seeed Xiao ESP32-S3 seeed-xiao-s3 esp32-s3
Station G2 station-g2 esp32-s3
Station G3 station-g3 esp32-s3
LILYGO T-Deck t-deck-tft esp32-s3
LILYGO T-Echo t-echo nrf52840
LILYGO T-Echo Plus t-echo-plus nrf52840
LILYGO T-Impulse Plus t-impulse-plus nrf52840
LilyGo T3-C6 tlora-c6 esp32-c6
Seeed SenseCAP T1000-E tracker-t1000-e nrf52840

Build artifacts expire on 2026-08-06. Updated for 9bc58e7.

@github-actions github-actions Bot added needs-review Needs human review enhancement New feature or request labels Jul 7, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/graphics/draw/MessageRenderer.cpp (1)

51-59: 📐 Maintainability & Code Quality | 🔵 Trivial

Duplicate failure-status classification.

showsFailureMark re-enumerates the same set of "failure" AckStatus values that MessageStatusText.cpp's switch statements implicitly classify. If a new failure status is added later and only one of the two lists is updated, the X-mark and the status text will disagree (mark shown without failure text, or vice versa).

Consider exposing a shared classifier (e.g., bool isFailureStatus(AckStatus)) from MessageStatusText/MessageStore that both the renderer and the text helper consume, so the two representations can't drift.

🤖 Prompt for 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.

In `@src/graphics/draw/MessageRenderer.cpp` around lines 51 - 59,
`showsFailureMark` is duplicating the failure classification already encoded in
`MessageStatusText.cpp`, so the X-mark and status text can drift apart. Replace
the hardcoded `AckStatus` list in `MessageRenderer.cpp` with a shared classifier
such as `isFailureStatus(AckStatus)` exposed from `MessageStatusText` or
`MessageStore`, and make both `showsFailureMark` and the status-text logic call
that same helper.
🤖 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 `@src/graphics/draw/NotificationRenderer.cpp`:
- Around line 521-527: Clamp lineCount before allocating and filling the picker
buffers in the NotificationRenderer logic. In the loop that populates
linePointers and when creating scratchLineBuffer, ensure the effective line
count is bounded by visibleTotalLines (or size both buffers from
std::max(lineCount, visibleTotalLines)) so linePointers[i] cannot exceed the
vector and the scratch buffer size never becomes negative. Use the existing
visibleTotalLines, lineCount, linePointers, and scratchLineBuffer symbols to
make the adjustment in place.

In `@src/mesh/MeshService.cpp`:
- Around line 198-204: The text-message handling block in
MeshService::handleReceived is adding local broadcasts to messageStore and the
UI a second time, which duplicates entries. Update this IF_SCREEN path so it
only calls messageStore.addFromPacket and
graphics::MessageRenderer::handleNewMessage for directed DMs (p.to != 0), and
skip or guard the local broadcast/channel case because Router::sendLocal already
routes those back through the normal receive path.

In `@src/modules/CannedMessageModule.cpp`:
- Around line 1050-1051: The routing-status check in CannedMessageModule should
treat NODENUM_BROADCAST_NO_LORA the same as NODENUM_BROADCAST, since the current
dest-based condition can misclassify no-LoRa broadcasts as DMs. Update the logic
around expectsRoutingStatus and p->want_ack to use the same broadcast handling
as isBroadcast(dest), or otherwise explicitly include both broadcast constants
in the condition, so the behavior stays consistent across all broadcast
destinations.

---

Nitpick comments:
In `@src/graphics/draw/MessageRenderer.cpp`:
- Around line 51-59: `showsFailureMark` is duplicating the failure
classification already encoded in `MessageStatusText.cpp`, so the X-mark and
status text can drift apart. Replace the hardcoded `AckStatus` list in
`MessageRenderer.cpp` with a shared classifier such as
`isFailureStatus(AckStatus)` exposed from `MessageStatusText` or `MessageStore`,
and make both `showsFailureMark` and the status-text logic call that same
helper.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 170f8953-e19e-4b48-aaf6-ad56b31293a6

📥 Commits

Reviewing files that changed from the base of the PR and between 392bac9 and dd80466.

⛔ Files ignored due to path filters (25)
  • artifacts/base-ui-message-status/admin-key-not-authorized.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/admin-session-expired.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/banner-delivered-mesh.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/banner-delivered-recipient.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/banner-failed-mesh.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/banner-recipient-key-unavailable.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/banner-recipient-needs-your-key.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/banner-relayed.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/channel-delivered.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/contact-sheet.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/dm-delivered.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/dm-relayed.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/duty-cycle-limit.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/failed-mesh.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/invalid-request.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/no-app-response.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/no-channel.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/no-interface.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/not-authorized.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/pki-failed.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/rate-limited.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/recipient-key-unavailable.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/recipient-needs-your-key.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/sending.png is excluded by !**/*.png
  • artifacts/base-ui-message-status/too-large.png is excluded by !**/*.png
📒 Files selected for processing (12)
  • artifacts/base-ui-message-status/README.md
  • src/MessageStore.cpp
  • src/MessageStore.h
  • src/graphics/draw/MessageRenderer.cpp
  • src/graphics/draw/MessageStatusText.cpp
  • src/graphics/draw/MessageStatusText.h
  • src/graphics/draw/NotificationRenderer.cpp
  • src/mesh/MeshService.cpp
  • src/modules/CannedMessageModule.cpp
  • src/modules/RoutingModule.cpp
  • test/native-suite-count
  • test/test_message_status_text/test_main.cpp

Comment thread src/graphics/draw/NotificationRenderer.cpp Outdated
Comment thread src/mesh/MeshService.cpp Outdated
Comment thread src/modules/CannedMessageModule.cpp
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Firmware Size Report

23 targets | vs develop: 21 increased, 1 decreased, net +450,856 (+440.3 KB)

Target Flash vs develop RAM RAM vs develop
picow 1,275,852 📈 +30,972 (+30.2 KB) 152,508 n/a
pico2w 1,250,480 📈 +29,964 (+29.3 KB) 158,988 n/a
rak11310 834,384 📈 +28,960 (+28.3 KB) 86,320 n/a
pico 811,632 📈 +28,944 (+28.3 KB) 85,876 n/a
seeed_xiao_rp2040 809,848 📈 +28,944 (+28.3 KB) 85,868 n/a
Show 18 more target(s)
Target Flash vs develop RAM RAM vs develop
pico2 797,816 📈 +28,040 (+27.4 KB) 92,376 n/a
seeed_xiao_rp2350 795,976 📈 +28,040 (+27.4 KB) 92,368 n/a
t-deck-tft 3,835,424 📈 +24,752 (+24.2 KB) 108,008 n/a
heltec-vision-master-e213-inkhud 2,249,328 📈 +21,968 (+21.5 KB) 92,400 n/a
elecrow-adv-35-tft 3,436,576 📈 +19,952 (+19.5 KB) 94,640 n/a
seeed-xiao-s3 2,295,520 📈 +19,376 (+18.9 KB) 102,056 n/a
station-g2 2,285,616 📈 +19,264 (+18.8 KB) 101,856 n/a
station-g3 2,285,616 📈 +19,264 (+18.8 KB) 101,856 n/a
rak3312 2,291,376 📈 +19,136 (+18.7 KB) 101,944 n/a
heltec-v3 2,283,120 📈 +19,040 (+18.6 KB) 130,224 n/a
rak11200 1,879,456 📈 +18,848 (+18.4 KB) 87,044 n/a
t-eth-elite 2,509,600 📈 +18,112 (+17.7 KB) 103,084 n/a
heltec-v4 2,294,864 📈 +17,568 (+17.2 KB) 101,112 n/a
heltec-ht62-esp32c3-sx1262 2,152,016 📈 +17,024 (+16.6 KB) 112,004 n/a
tlora-c6 2,383,616 📈 +15,312 (+15.0 KB) 102,764 n/a
rak3172 182,664 📉 -3,632 (-3.5 KB) 25,008 n/a
wio-e5 239,636 📈 +1,008 26,640 n/a
meshnology_w10 2,465,632 136,212 n/a

Size budgets

Env Metric Measured Budget Used
rak4631 RAM (.data+.bss) n/a 113,000 n/a
rak4631 flash n/a 786,000 n/a

Budgets live in bin/ram_budgets.json and are raised deliberately in the PR that needs the headroom - never automatically.


Updated for 5630093

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
bin/collect_sizes.py (1)

23-30: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Silent overwrite risk on duplicate board manifests.

Recursive discovery makes it more likely that two manifests (e.g. from separate downloaded-artifact subdirectories) resolve to the same board key. The unconditional sizes[board] = entry assignment at line 64 will silently keep whichever manifest sorts last, with no signal that a duplicate was dropped, which could mask a real size regression in the discarded manifest.

♻️ Suggested guard for duplicate board keys
         if bin_size is not None:
             entry = {"flash_bytes": bin_size}
             ram_bytes = data.get("ram_bytes")
             if isinstance(ram_bytes, int) and not isinstance(ram_bytes, bool):
                 entry["ram_bytes"] = ram_bytes
+            if board in sizes:
+                print(f"warning: duplicate manifest for board '{board}', overwriting", file=sys.stderr)
             sizes[board] = entry
🤖 Prompt for 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.

In `@bin/collect_sizes.py` around lines 23 - 30, The recursive manifest scan in
collect_sizes.py can produce duplicate board keys, and the current
entry-building path silently overwrites earlier results when sizes[board] is
assigned. Update the manifest processing logic around manifest_paths, the
per-file loop, and the board key handling to detect duplicates before writing
into sizes; when the same board appears more than once, either fail fast or emit
a clear warning with both manifest paths so the duplicate cannot be silently
dropped.
🤖 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.

Nitpick comments:
In `@bin/collect_sizes.py`:
- Around line 23-30: The recursive manifest scan in collect_sizes.py can produce
duplicate board keys, and the current entry-building path silently overwrites
earlier results when sizes[board] is assigned. Update the manifest processing
logic around manifest_paths, the per-file loop, and the board key handling to
detect duplicates before writing into sizes; when the same board appears more
than once, either fail fast or emit a clear warning with both manifest paths so
the duplicate cannot be silently dropped.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 15ddc0cb-9cdd-4a34-9dc2-6f82e283de45

📥 Commits

Reviewing files that changed from the base of the PR and between 7399a90 and f5cece5.

📒 Files selected for processing (2)
  • bin/collect_sizes.py
  • bin/test_size_scripts.py

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
bin/test_size_scripts.py (1)

192-192: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unused stdout variable.

Static analysis flags stdout from run_script as unused here.

🧹 Proposed fix
-        rc, stdout, stderr = run_script("collect_sizes.py", [tmpdir, outfile])
+        rc, _stdout, stderr = run_script("collect_sizes.py", [tmpdir, outfile])
🤖 Prompt for 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.

In `@bin/test_size_scripts.py` at line 192, The `run_script` result in the
`collect_sizes.py` test currently binds `stdout` but never uses it, so update
the assignment in `test_size_scripts.py` to ignore that value while keeping `rc`
and `stderr` for the assertion path. Locate the call inside the size-script test
helper and remove the unused `stdout` binding to satisfy static analysis without
changing test behavior.

Source: Linters/SAST tools

🤖 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.

Nitpick comments:
In `@bin/test_size_scripts.py`:
- Line 192: The `run_script` result in the `collect_sizes.py` test currently
binds `stdout` but never uses it, so update the assignment in
`test_size_scripts.py` to ignore that value while keeping `rc` and `stderr` for
the assertion path. Locate the call inside the size-script test helper and
remove the unused `stdout` binding to satisfy static analysis without changing
test behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2b31a33e-e0e3-43dd-b763-2db0075e0352

📥 Commits

Reviewing files that changed from the base of the PR and between f5cece5 and 2edd16f.

📒 Files selected for processing (2)
  • bin/collect_sizes.py
  • bin/test_size_scripts.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • bin/collect_sizes.py

@Xaositek Xaositek marked this pull request as draft July 7, 2026 15:02
@Xaositek

Xaositek commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Do not merge until screen shots of regression testing is completed.

@Xaositek

Xaositek commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Also things like should not be included in this PR
collect_sizes.py
test_size_scripts.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request needs-review Needs human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants