Skip to content

Align web message status wording and evidence#1251

Draft
RCGV1 wants to merge 15 commits into
meshtastic:mainfrom
RCGV1:codex/message-status-alignment
Draft

Align web message status wording and evidence#1251
RCGV1 wants to merge 15 commits into
meshtastic:mainfrom
RCGV1:codex/message-status-alignment

Conversation

@RCGV1

@RCGV1 RCGV1 commented Jul 7, 2026

Copy link
Copy Markdown
Member

Source issues

Summary

  • Aligns web message status text with the design issue source of truth, including visible sender status text, explicit vs implicit ACK wording, retryable vs permanent failures, and screen-reader labels that match visible text.
  • Maps the expanded firmware routing-error vocabulary to user-facing text, including radio/interface, duty-cycle, rate-limit, app-response, authorization, PKI key, and admin key/session cases.
  • Preserves routing errors and message status ordering through chat persistence so failed/relayed state can render the correct status.
  • Mirrors the expanded deliveryStatus key structure across locale catalogs.

UI validation

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

Web message status overview

Validation

  • pnpm exec vitest run apps/web/src/components/PageComponents/Messages/messageDeliveryStatus.test.ts passed: 1 file, 19 tests.
  • pnpm exec vitest run packages/sdk-storage-sqlocal/src/schema/migrations.test.ts passed: 1 file, 9 tests.
  • pnpm run lint passed with existing warnings.
  • NODE_OPTIONS=--no-webstorage pnpm run test passed: 71 files, 434 tests.
  • pnpm --filter "./apps/web" run build passed locally.

Hardware verification

Not yet performed. This PR is draft until hardware/real-device verification is complete.

Notes

  • Vercel preview remains blocked by the Meshtastic team authorization prompt for fork deployments.

Copilot AI review requested due to automatic review settings July 7, 2026 05:18
@vercel

vercel Bot commented Jul 7, 2026

Copy link
Copy Markdown

@RCGV1 is attempting to deploy a commit to the Meshtastic Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds relayed message-state and routing-error tracking across SDK contracts, persistence, ChatClient routing, web delivery-status rendering, retry wiring, and localized delivery-status strings.

Changes

Message delivery status and retry

Layer / File(s) Summary
Domain contracts
packages/sdk/src/features/chat/domain/MessageState.ts, Message.ts, MessageRepository.ts, packages/sdk/src/features/chat/infrastructure/MessageMapper.ts, index.ts, packages/sdk/mod.ts, packages/sdk/src/core/packet-codec/decodePacket.ts, packages/sdk/src/core/types.ts
Adds Relayed, precedence helpers, routing-error fields and signatures, plus packet requestId metadata and related re-exports.
In-memory, store, and sqlite persistence
packages/sdk/src/features/chat/infrastructure/repositories/InMemoryMessageRepository{.ts,.test.ts}, packages/sdk/src/features/chat/state/chatStore.ts, packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository{.ts,.test.ts}, packages/sdk-storage-sqlocal/src/schema/chat.ts, migrations{.ts,.test.ts}
Adds precedence-gated state updates, conversation-key inference, routing-error persistence, and matching store/repository/schema/migration coverage.
ChatClient routing and persistence
packages/sdk/src/features/chat/ChatClient.ts, ChatClient.send.test.ts, ChatClient.persistence.test.ts
Reworks routing-state derivation and persistence sequencing, and adds coverage for relayed, acked, and failed transitions.
Web delivery status helper
apps/web/src/components/PageComponents/Messages/messageDeliveryStatus{.ts,.test.ts}, apps/web/public/i18n/locales/en/messages.json
Adds shared delivery-status metadata, retryability, detail text, and updated English localization entries.
Retry UI wiring
apps/web/src/components/PageComponents/Messages/{MessageItem,ChannelChat}.tsx, apps/web/src/pages/Messages.tsx, apps/web/src/core/hooks/useChat{AsLegacyMessages,Legacy}.ts, apps/web/src/core/stores/messageStore/index.ts, apps/web/src/core/subscriptions{.ts,.test.ts}
Passes retry callbacks through message rendering, adds resend logic, maps relayed state in legacy paths, and changes routing-error handling in subscriptions.
Localized delivery status strings
apps/web/public/i18n/locales/*/messages.json
Replaces delivery-status translation blocks across locales with the expanded status keys and the new displayText/detailText schema.

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

Possibly related issues

Poem

A rabbit hopped through relay light,
With ack and fail kept neat in sight.
When messages stumble, retry can bloom,
And detail text brightens the room.
🐇🥕

🚥 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 reflects the main change: updating web message status wording and related evidence.
Description check ✅ Passed The PR description covers the summary, related issues, testing, screenshots, and validation details, with only the checklist left out.

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR aligns chat message delivery status semantics and wording across the SDK and web UI, including persisting richer routing error context so historical messages can render the correct state and failure reason after reload.

Changes:

  • Added a Relayed intermediate message state plus precedence rules to prevent state “downgrades” (e.g., AckRelayed).
  • Persisted routingError alongside message state (in-memory + sqlocal storage), including schema/migration updates to dedupe and re-key legacy direct-message conversation buckets.
  • Updated the web Messages UI to display expanded delivery/failure wording (with SR-friendly labels) and added a “Retry” affordance for retryable states.

Reviewed changes

Copilot reviewed 30 out of 53 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/sdk/src/features/chat/state/chatStore.ts Adds message lookup and state/routing-error update gating (precedence + no-op detection).
packages/sdk/src/features/chat/infrastructure/repositories/InMemoryMessageRepository.ts Supports explicit conversation keys, preserves direct-message bucketing via localNodeNum, and persists routingError.
packages/sdk/src/features/chat/infrastructure/repositories/InMemoryMessageRepository.test.ts Extends tests to cover routingError persistence, state precedence, and direct bucketing rules.
packages/sdk/src/features/chat/infrastructure/MessageMapper.ts Initializes mapped messages with routingError: undefined.
packages/sdk/src/features/chat/index.ts Re-exports message-state precedence helpers for downstream usage.
packages/sdk/src/features/chat/domain/MessageState.ts Introduces Relayed and precedence/upgrade helpers.
packages/sdk/src/features/chat/domain/MessageRepository.ts Extends repository contract to accept optional conversation key + routingError on updates.
packages/sdk/src/features/chat/domain/Message.ts Adds optional routingError to the message domain model.
packages/sdk/src/features/chat/ChatClient.ts Tracks requestId vs packet id, computes Relayed vs Ack, and serializes persistence of append vs state updates.
packages/sdk/src/features/chat/ChatClient.send.test.ts Adds coverage for requestId matching, relayed-vs-recipient ACK semantics, and routing error persistence.
packages/sdk/src/features/chat/ChatClient.persistence.test.ts Adds ordering tests to ensure final state wins in persistence races.
packages/sdk/src/core/types.ts Adds optional requestId to PacketMetadata.
packages/sdk/src/core/packet-codec/decodePacket.ts Populates PacketMetadata.requestId from decoded data packets.
packages/sdk/mod.ts Exposes message-state precedence helpers at the SDK top-level exports.
packages/sdk-storage-sqlocal/src/schema/migrations.ts Adds routing_error, dedupes by state precedence, creates unique index, and re-keys legacy outbound direct conversations.
packages/sdk-storage-sqlocal/src/schema/migrations.test.ts Adds tests for the new unique index and direct-message re-keying behaviors (including ambiguous-history no-op cases).
packages/sdk-storage-sqlocal/src/schema/chat.ts Extends messages schema with relayed + routing_error and defines a unique device+id index.
packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.ts Stores routingError, infers direct conversation by local node, prevents state downgrades at update time, and uses explicit conv keys for inserts/notifications.
packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.test.ts Adds routingError/state precedence tests and direct-message reload/bucketing tests.
apps/web/src/pages/Messages.tsx Adds a retry callback and passes it through to chat rendering.
apps/web/src/core/subscriptions.ts Removes legacy refreshKeys dialog trigger for routing errors now handled elsewhere.
apps/web/src/core/subscriptions.test.ts Adds regression test ensuring refreshKeys is not opened for NO_CHANNEL/PKI_UNKNOWN_PUBKEY.
apps/web/src/core/stores/messageStore/index.ts Extends legacy message shape with Relayed + optional routingError.
apps/web/src/core/hooks/useChatLegacy.ts Maps SDK message routingError + relayed state into legacy message shape.
apps/web/src/core/hooks/useChatAsLegacyMessages.ts Same as above for the adapter used by Messages UI.
apps/web/src/components/PageComponents/Messages/MessageItem.tsx Switches to centralized delivery-status mapping, displays detail text in tooltip, and adds a Retry button.
apps/web/src/components/PageComponents/Messages/messageDeliveryStatus.ts New mapping layer from message state/routing error to visible text, tooltip detail, icon, and retryability.
apps/web/src/components/PageComponents/Messages/messageDeliveryStatus.test.ts Unit tests for the new delivery-status mapping and per-error wording.
apps/web/src/components/PageComponents/Messages/ChannelChat.tsx Plumbs retry handler down to MessageItem.
apps/web/public/i18n/locales/en/messages.json Replaces legacy delivery status strings with expanded, design-aligned wording and retry labels.

Comment on lines 155 to 158
const isSender = myNodeNum !== undefined && message.from === myNodeNum;
const isOnPrimaryChannel = message.channel === Types.ChannelNumber.Primary; // Use the enum
const shouldShowStatusIcon = isSender && isOnPrimaryChannel;
const shouldShowStatus = isSender;
const canRetry = shouldShowStatus && messageStatusInfo.canRetry && onRetry;

Comment on lines +223 to +226
size="sm"
className="h-5 px-1.5 text-xs text-slate-600 hover:text-slate-950 dark:text-slate-300 dark:hover:text-white"
onClick={() => onRetry(message)}
aria-label={t("deliveryStatus.retryAriaLabel", {
Comment on lines 82 to 85
<TooltipContent className="bg-slate-800 dark:bg-slate-600 text-white px-4 py-1 rounded text-xs">
{statusInfo.displayText}
{statusInfo.detailText}
<TooltipArrow className="fill-slate-800" />
</TooltipContent>

@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: 1

🧹 Nitpick comments (6)
packages/sdk-storage-sqlocal/src/schema/migrations.ts (1)

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

Unused aggregates in direct_buckets.

peer_node (MIN(to_node)) and message_count (COUNT(*)) are computed but never referenced by the downstream CTEs or the UPDATE. Only recipient_count and actionable_count are used. Dropping the unused aggregates keeps the migration lean.

🤖 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 `@packages/sdk-storage-sqlocal/src/schema/migrations.ts` around lines 103 -
119, The direct_buckets CTE in migrations.ts is computing aggregates that are
never used downstream; remove the unused peer_node and message_count fields from
the SELECT while keeping recipient_count and actionable_count. Update the
direct_buckets query so it only projects values referenced by the later CTEs and
UPDATE, using the existing direct_buckets symbol as the place to make the
cleanup.
packages/sdk-storage-sqlocal/src/schema/chat.ts (1)

32-37: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Redundant index on (device_id, id).

pk: index("messages_pk") and deviceMessageUnique: uniqueIndex("idx_messages_device_id_id_unique") cover the exact same columns. The unique index fully serves any lookup the plain index would, so messages_pk is now dead weight (extra storage and per-write maintenance). Consider dropping it from the schema (plus a DROP INDEX in a migration for existing DBs).

🤖 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 `@packages/sdk-storage-sqlocal/src/schema/chat.ts` around lines 32 - 37, The
schema in chat.ts defines two indexes on the same `(deviceId, id)` columns: `pk`
and `deviceMessageUnique`, making `messages_pk` redundant. Remove the plain `pk:
index("messages_pk")` from the table definition and keep the unique index
`deviceMessageUnique` as the sole lookup/index for those columns. If existing
databases already have `messages_pk`, add a migration to drop that index so the
schema and on-disk DB stay aligned.
packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.ts (1)

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

Reuse the schema-inferred MessageRow type. packages/sdk-storage-sqlocal/src/schema/chat.ts already exports MessageRow = typeof messages.$inferSelect, so this local interface can drift from the schema. Import the shared type instead.

🤖 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 `@packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.ts` around
lines 205 - 217, The local MessageRow interface in SqlocalMessageRepository
should not duplicate the chat schema. Remove the inline interface and import the
shared MessageRow type exported from schema/chat.ts so the repository uses the
schema-inferred shape directly. Update any references in
SqlocalMessageRepository to rely on that imported type and keep the repository
aligned with the messages table definition.
packages/sdk/src/features/chat/domain/MessageState.ts (1)

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

Document the precedence rule here. The Pending < Relayed < Failed < Ack order is easy to misread; a short note explaining that Failed can replace Relayed while Ack remains terminal would help prevent accidental reordering.

🤖 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 `@packages/sdk/src/features/chat/domain/MessageState.ts` around lines 8 - 17,
Document the ordering rule in getMessageStatePrecedence and the
messageStatePrecedence map so the intent is explicit: Pending < Relayed < Failed
< Ack, with Failed allowed to replace Relayed while Ack stays terminal. Add a
short comment near the MessageState precedence table in MessageState.ts
explaining that the numeric values are deliberate and should not be reordered
without preserving this transition behavior.
apps/web/src/core/subscriptions.test.ts (1)

30-49: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Test only verifies the negative case; consider also asserting the dialog still opens for the case(s) meant to keep triggering it.

As written, this test would pass even if setDialogOpen were never called from onRoutingPacket at all (i.e., if the refreshKeys trigger were removed outright rather than being correctly scoped away from NO_CHANNEL/PKI_UNKNOWN_PUBKEY). Consider adding a companion case that still exercises the intended remaining refreshKeys trigger to guard against accidental full removal.

🤖 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 `@apps/web/src/core/subscriptions.test.ts` around lines 30 - 49, The
subscribeAll routing error test only checks that refreshKeys is not opened for
NO_CHANNEL and PKI_UNKNOWN_PUBKEY, so it could still pass if the onRoutingPacket
path stopped opening the dialog entirely. Update the tests in
subscriptions.test.ts to keep the existing negative assertions and add a
companion case that dispatches a routing reason meant to still trigger
refreshKeys, then assert device.setDialogOpen is called. Use subscribeAll,
onRoutingPacket, and setDialogOpen to anchor the new coverage.
packages/sdk/src/features/chat/ChatClient.ts (1)

315-360: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider logging persistence failures instead of silently swallowing them.

persistAppend/persistStateUpdate intentionally swallow repository errors "to avoid breaking reactive UI updates," but a silent catch {} means if repository.append fails, the subsequent persistStateUpdate for that message id becomes a no-op (row never existed to update), and the failure is invisible until the user reloads and finds the message/state missing or stale. A minimal this.client.log.error(...) (or similar) inside each catch would preserve the "don't break reactive flow" behavior while making silent data-loss diagnosable.

♻️ Suggested logging addition
       try {
         await this.repository.append(message, conv);
         if (this.retention) await this.repository.prune(this.retention);
-      } catch {
+      } catch (err) {
+        this.client.log.error("ChatClient", `persistAppend failed: ${err}`);
         // persistence failure must not break reactive flow
       }
🤖 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 `@packages/sdk/src/features/chat/ChatClient.ts` around lines 315 - 360, Both
persistAppend and persistStateUpdate currently swallow repository errors, which
hides data-loss and makes failed persistence impossible to diagnose. Update the
catch blocks in ChatClient.persistAppend and ChatClient.persistStateUpdate to
log the failure through the existing client logging mechanism (for example,
this.client.log.error) while still preserving the non-throwing reactive flow.
Include enough context to identify the operation and message/conversation
identifiers, and keep the pendingMessagePersistence and pendingStatePersistence
cleanup logic unchanged.
🤖 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 `@apps/web/public/i18n/locales/en/messages.json`:
- Around line 22-101: Update the locale message catalogs to match the new nested
deliveryStatus structure in messages.json, since the current translations still
expose the old flat keys and will fall back to English. In each non-English
messages.json, replace the old delivery status entries with the new nested
symbols such as deliveryStatus.deliveredToMesh,
deliveryStatus.deliveredToRecipient, deliveryStatus.encryptedSendFailed,
deliveryStatus.failedToMesh, deliveryStatus.noChannel, deliveryStatus.sending,
and deliveryStatus.unknown so the UI can resolve localized strings correctly.
Keep the same displayText/detailText shape and ensure every locale mirrors the
English key set exactly.

---

Nitpick comments:
In `@apps/web/src/core/subscriptions.test.ts`:
- Around line 30-49: The subscribeAll routing error test only checks that
refreshKeys is not opened for NO_CHANNEL and PKI_UNKNOWN_PUBKEY, so it could
still pass if the onRoutingPacket path stopped opening the dialog entirely.
Update the tests in subscriptions.test.ts to keep the existing negative
assertions and add a companion case that dispatches a routing reason meant to
still trigger refreshKeys, then assert device.setDialogOpen is called. Use
subscribeAll, onRoutingPacket, and setDialogOpen to anchor the new coverage.

In `@packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.ts`:
- Around line 205-217: The local MessageRow interface in
SqlocalMessageRepository should not duplicate the chat schema. Remove the inline
interface and import the shared MessageRow type exported from schema/chat.ts so
the repository uses the schema-inferred shape directly. Update any references in
SqlocalMessageRepository to rely on that imported type and keep the repository
aligned with the messages table definition.

In `@packages/sdk-storage-sqlocal/src/schema/chat.ts`:
- Around line 32-37: The schema in chat.ts defines two indexes on the same
`(deviceId, id)` columns: `pk` and `deviceMessageUnique`, making `messages_pk`
redundant. Remove the plain `pk: index("messages_pk")` from the table definition
and keep the unique index `deviceMessageUnique` as the sole lookup/index for
those columns. If existing databases already have `messages_pk`, add a migration
to drop that index so the schema and on-disk DB stay aligned.

In `@packages/sdk-storage-sqlocal/src/schema/migrations.ts`:
- Around line 103-119: The direct_buckets CTE in migrations.ts is computing
aggregates that are never used downstream; remove the unused peer_node and
message_count fields from the SELECT while keeping recipient_count and
actionable_count. Update the direct_buckets query so it only projects values
referenced by the later CTEs and UPDATE, using the existing direct_buckets
symbol as the place to make the cleanup.

In `@packages/sdk/src/features/chat/ChatClient.ts`:
- Around line 315-360: Both persistAppend and persistStateUpdate currently
swallow repository errors, which hides data-loss and makes failed persistence
impossible to diagnose. Update the catch blocks in ChatClient.persistAppend and
ChatClient.persistStateUpdate to log the failure through the existing client
logging mechanism (for example, this.client.log.error) while still preserving
the non-throwing reactive flow. Include enough context to identify the operation
and message/conversation identifiers, and keep the pendingMessagePersistence and
pendingStatePersistence cleanup logic unchanged.

In `@packages/sdk/src/features/chat/domain/MessageState.ts`:
- Around line 8-17: Document the ordering rule in getMessageStatePrecedence and
the messageStatePrecedence map so the intent is explicit: Pending < Relayed <
Failed < Ack, with Failed allowed to replace Relayed while Ack stays terminal.
Add a short comment near the MessageState precedence table in MessageState.ts
explaining that the numeric values are deliberate and should not be reordered
without preserving this transition behavior.
🪄 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: 3416d911-6fdb-441d-9b0a-d139d4a181db

📥 Commits

Reviewing files that changed from the base of the PR and between ec0c91a and e35dbfd.

⛔ Files ignored due to path filters (23)
  • validation-artifacts/message-status/admin-key-not-authorized.png is excluded by !**/*.png
  • validation-artifacts/message-status/admin-session-expired.png is excluded by !**/*.png
  • validation-artifacts/message-status/channel-implicit-ack.png is excluded by !**/*.png
  • validation-artifacts/message-status/delivered-to-mesh.png is excluded by !**/*.png
  • validation-artifacts/message-status/delivered-to-recipient.png is excluded by !**/*.png
  • validation-artifacts/message-status/dm-implicit-ack.png is excluded by !**/*.png
  • validation-artifacts/message-status/duty-cycle-limit.png is excluded by !**/*.png
  • validation-artifacts/message-status/encrypted-send-failed.png is excluded by !**/*.png
  • validation-artifacts/message-status/explicit-ack.png is excluded by !**/*.png
  • validation-artifacts/message-status/failed-to-mesh.png is excluded by !**/*.png
  • validation-artifacts/message-status/invalid-request.png is excluded by !**/*.png
  • validation-artifacts/message-status/message-too-large.png is excluded by !**/*.png
  • validation-artifacts/message-status/no-ack.png is excluded by !**/*.png
  • validation-artifacts/message-status/no-app-response.png is excluded by !**/*.png
  • validation-artifacts/message-status/no-channel.png is excluded by !**/*.png
  • validation-artifacts/message-status/no-radio-interface.png is excluded by !**/*.png
  • validation-artifacts/message-status/not-authorized.png is excluded by !**/*.png
  • validation-artifacts/message-status/overview.png is excluded by !**/*.png
  • validation-artifacts/message-status/rate-limited.png is excluded by !**/*.png
  • validation-artifacts/message-status/recipient-key-unavailable.png is excluded by !**/*.png
  • validation-artifacts/message-status/recipient-needs-your-key.png is excluded by !**/*.png
  • validation-artifacts/message-status/relayed.png is excluded by !**/*.png
  • validation-artifacts/message-status/sending.png is excluded by !**/*.png
📒 Files selected for processing (30)
  • apps/web/public/i18n/locales/en/messages.json
  • apps/web/src/components/PageComponents/Messages/ChannelChat.tsx
  • apps/web/src/components/PageComponents/Messages/MessageItem.tsx
  • apps/web/src/components/PageComponents/Messages/messageDeliveryStatus.test.ts
  • apps/web/src/components/PageComponents/Messages/messageDeliveryStatus.ts
  • apps/web/src/core/hooks/useChatAsLegacyMessages.ts
  • apps/web/src/core/hooks/useChatLegacy.ts
  • apps/web/src/core/stores/messageStore/index.ts
  • apps/web/src/core/subscriptions.test.ts
  • apps/web/src/core/subscriptions.ts
  • apps/web/src/pages/Messages.tsx
  • packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.test.ts
  • packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.ts
  • packages/sdk-storage-sqlocal/src/schema/chat.ts
  • packages/sdk-storage-sqlocal/src/schema/migrations.test.ts
  • packages/sdk-storage-sqlocal/src/schema/migrations.ts
  • packages/sdk/mod.ts
  • packages/sdk/src/core/packet-codec/decodePacket.ts
  • packages/sdk/src/core/types.ts
  • packages/sdk/src/features/chat/ChatClient.persistence.test.ts
  • packages/sdk/src/features/chat/ChatClient.send.test.ts
  • packages/sdk/src/features/chat/ChatClient.ts
  • packages/sdk/src/features/chat/domain/Message.ts
  • packages/sdk/src/features/chat/domain/MessageRepository.ts
  • packages/sdk/src/features/chat/domain/MessageState.ts
  • packages/sdk/src/features/chat/index.ts
  • packages/sdk/src/features/chat/infrastructure/MessageMapper.ts
  • packages/sdk/src/features/chat/infrastructure/repositories/InMemoryMessageRepository.test.ts
  • packages/sdk/src/features/chat/infrastructure/repositories/InMemoryMessageRepository.ts
  • packages/sdk/src/features/chat/state/chatStore.ts
💤 Files with no reviewable changes (1)
  • apps/web/src/core/subscriptions.ts

Comment on lines 22 to 101
"deliveryStatus": {
"delivered": {
"label": "Message delivered",
"displayText": "Message delivered"
"retry": "Retry",
"retryAriaLabel": "Retry message: {{status}}",
"deliveredToMesh": {
"displayText": "Delivered to mesh",
"detailText": "At least one node heard this channel message."
},
"failed": {
"label": "Message delivery failed",
"displayText": "Delivery failed"
"deliveredToRecipient": {
"displayText": "Delivered to recipient",
"detailText": "The recipient confirmed this direct message."
},
"unknown": {
"label": "Message status unknown",
"displayText": "Unknown state"
"encryptedSendFailed": {
"displayText": "Could not send encrypted message",
"detailText": "The radio could not create the encrypted path for this message. Let node info sync, then try again."
},
"adminKeyNotAuthorized": {
"displayText": "Admin key not authorized",
"detailText": "The admin public key is not authorized on the destination."
},
"adminSessionExpired": {
"displayText": "Admin session expired",
"detailText": "The admin session key is missing, invalid, or expired. Start a new admin session, then try again."
},
"dutyCycleLimit": {
"displayText": "Duty cycle limit",
"detailText": "The radio is temporarily blocked by the regional airtime limit. Try again later."
},
"failedToMesh": {
"displayText": "Failed to deliver to mesh",
"detailText": "No node confirmed this message. Try again when you have better signal or more mesh coverage."
},
"invalidRequest": {
"displayText": "Invalid request",
"detailText": "The receiving app rejected the request. Check the message or command and try again."
},
"messageTooLarge": {
"displayText": "Message is too large to send",
"detailText": "Shorten the message and send it again."
},
"noAppResponse": {
"displayText": "No app response",
"detailText": "The destination received the request, but no app or module responded."
},
"noChannel": {
"displayText": "Channel/key mismatch",
"detailText": "This message could not be encoded or decoded with a matching channel/key. Check the channel and key, then try again."
},
"waiting": {
"label": "Sending message",
"displayText": "Waiting for delivery"
"noRadioInterface": {
"displayText": "No radio interface",
"detailText": "The radio does not have a usable interface for this send."
},
"notAuthorized": {
"displayText": "Not authorized",
"detailText": "The destination refused permission for this request."
},
"rateLimited": {
"displayText": "Rate limited",
"detailText": "Messages are being sent too quickly. Wait a moment, then try again."
},
"recipientKeyUnavailable": {
"displayText": "Recipient key unavailable",
"detailText": "Your node does not have the recipient's public key yet. Wait for node info to sync, then try again."
},
"recipientNeedsYourKey": {
"displayText": "Recipient needs your key",
"detailText": "The recipient does not know your public key yet. Your node may share its info automatically; try again after it syncs."
},
"relayed": {
"displayText": "Relayed, not confirmed by recipient",
"detailText": "A node relayed this message, but the recipient has not confirmed it."
},
"sending": {
"displayText": "Sending...",
"detailText": "The radio is still trying to send this message."
},
"unknown": {
"displayText": "Message status unknown",
"detailText": "The message status is not available."
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether other locales still use the old deliveryStatus schema.
fd messages.json apps/web/public/i18n/locales -x sh -c 'echo "== {} =="; jq ".deliveryStatus" {}'

Repository: meshtastic/web

Length of output: 12686


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== deliveryStatus usages ==\n'
rg -n '"deliveryStatus"|deliveryStatus\.' apps/web -g '!**/node_modules/**'

printf '\n== locale lookup / fallback hints ==\n'
rg -n 'fallback|i18n|locales/' apps/web/src apps/web/public -g '!**/node_modules/**' | head -n 200

Repository: meshtastic/web

Length of output: 31712


🏁 Script executed:

#!/bin/bash
set -euo pipefail

cat -n apps/web/src/i18n-config.ts | sed -n '1,120p'

Repository: meshtastic/web

Length of output: 2387


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== en/ui deliveryStatus ==\n'
jq '.deliveryStatus' apps/web/public/i18n/locales/en/ui.json

printf '\n== de-DE/ui deliveryStatus ==\n'
jq '.deliveryStatus' apps/web/public/i18n/locales/de-DE/ui.json

printf '\n== zh-TW/ui deliveryStatus ==\n'
jq '.deliveryStatus' apps/web/public/i18n/locales/zh-TW/ui.json

Repository: meshtastic/web

Length of output: 257


Update the localized deliveryStatus entries in the other messages.json files.
Several locales still use the old flat keys (delivered/failed/waiting/unknown), so these new nested lookups will fall back to English for non-English users.

🤖 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 `@apps/web/public/i18n/locales/en/messages.json` around lines 22 - 101, Update
the locale message catalogs to match the new nested deliveryStatus structure in
messages.json, since the current translations still expose the old flat keys and
will fall back to English. In each non-English messages.json, replace the old
delivery status entries with the new nested symbols such as
deliveryStatus.deliveredToMesh, deliveryStatus.deliveredToRecipient,
deliveryStatus.encryptedSendFailed, deliveryStatus.failedToMesh,
deliveryStatus.noChannel, deliveryStatus.sending, and deliveryStatus.unknown so
the UI can resolve localized strings correctly. Keep the same
displayText/detailText shape and ensure every locale mirrors the English key set
exactly.

@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: 5

🤖 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 `@apps/web/public/i18n/locales/bg-BG/messages.json`:
- Around line 22-98: Translate the `deliveryStatus` entries in `messages.json`
to Bulgarian so the locale is consistent with the rest of the file; update the
string values for the related status objects such as `retry`, `deliveredToMesh`,
`encryptedSendFailed`, `failedToMesh`, `recipientKeyUnavailable`, `sending`, and
`unknown` while preserving the existing keys and placeholders like `{{status}}`.

In `@apps/web/public/i18n/locales/it-IT/messages.json`:
- Around line 22-98: The delivery-status entries in messages.json are still in
English, so replace the untranslated values for keys like retry, retryAriaLabel,
deliveredToMesh, deliveredToRecipient, encryptedSendFailed, and the other status
objects in this locale file with proper Italian text. Keep the existing JSON
structure and update both displayText and detailText strings consistently across
all affected message status keys.

In `@apps/web/public/i18n/locales/nl-NL/messages.json`:
- Around line 22-98: The deliveryStatus entries in messages.json are still in
English and need Dutch localization. Replace the displayText and detailText
values for each status key under this block with Dutch translations, keeping the
existing keys and structure intact. Use the deliveryStatus object in
nl-NL/messages.json to update all affected status strings consistently.

In `@apps/web/public/i18n/locales/sv-SE/messages.json`:
- Around line 22-98: The delivery-status strings in the sv-SE locale are still
in English, so update the message entries in the translation object to Swedish
before merging. Translate each delivery-related label and detail text
consistently in the messages JSON, keeping the existing keys such as retry,
deliveredToMesh, deliveredToRecipient, encryptedSendFailed, failedToMesh,
noChannel, and unknown unchanged while replacing only the user-facing copy.

In `@apps/web/public/i18n/locales/zh-TW/messages.json`:
- Around line 22-98: The new deliveryStatus entries in messages.json are still
in English and need Traditional Chinese translations before merge. Update the
localized strings for the status labels and detail text in this block, keeping
the existing keys and structure intact, and make sure the translations are
applied consistently across all entries such as retry, deliveredToMesh,
failedToMesh, and unknown.
🪄 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: facc19cc-4ef4-4ccf-a4e6-68c928ef55cf

📥 Commits

Reviewing files that changed from the base of the PR and between 5074859 and bb47b71.

📒 Files selected for processing (21)
  • apps/web/public/i18n/locales/be-BY/messages.json
  • apps/web/public/i18n/locales/bg-BG/messages.json
  • apps/web/public/i18n/locales/cs-CZ/messages.json
  • apps/web/public/i18n/locales/de-DE/messages.json
  • apps/web/public/i18n/locales/es-ES/messages.json
  • apps/web/public/i18n/locales/fi-FI/messages.json
  • apps/web/public/i18n/locales/fr-FR/messages.json
  • apps/web/public/i18n/locales/hu-HU/messages.json
  • apps/web/public/i18n/locales/it-IT/messages.json
  • apps/web/public/i18n/locales/ja-JP/messages.json
  • apps/web/public/i18n/locales/ko-KR/messages.json
  • apps/web/public/i18n/locales/nl-NL/messages.json
  • apps/web/public/i18n/locales/pl-PL/messages.json
  • apps/web/public/i18n/locales/pt-BR/messages.json
  • apps/web/public/i18n/locales/pt-PT/messages.json
  • apps/web/public/i18n/locales/ru-RU/messages.json
  • apps/web/public/i18n/locales/sv-SE/messages.json
  • apps/web/public/i18n/locales/tr-TR/messages.json
  • apps/web/public/i18n/locales/uk-UA/messages.json
  • apps/web/public/i18n/locales/zh-CN/messages.json
  • apps/web/public/i18n/locales/zh-TW/messages.json

Comment thread apps/web/public/i18n/locales/bg-BG/messages.json Outdated
Comment thread apps/web/public/i18n/locales/it-IT/messages.json Outdated
Comment thread apps/web/public/i18n/locales/nl-NL/messages.json Outdated
Comment thread apps/web/public/i18n/locales/sv-SE/messages.json Outdated
Comment thread apps/web/public/i18n/locales/zh-TW/messages.json Outdated
@RCGV1
RCGV1 marked this pull request as draft July 7, 2026 15:45
@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
web-test Ready Ready Preview, Comment Jul 9, 2026 7:06pm

Request Review

@danditomaso

Copy link
Copy Markdown
Collaborator

@RCGV1 Wanted to check in on these draft PR's. Do you think you'll have time to get them over the line or did you need a hand?

@RCGV1

RCGV1 commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

If you can help me test it that would be great. I don't want to make it ready without fully testing.

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.

3 participants