Skip to content

feat(reticulum): RMAP X of Y status and RNCP catch-up dedupe - #751

Merged
rinchen merged 4 commits into
mainfrom
feat/reticulum-rmap-status-rncp-dedup
Jul 31, 2026
Merged

feat(reticulum): RMAP X of Y status and RNCP catch-up dedupe#751
rinchen merged 4 commits into
mainfrom
feat/reticulum-rmap-status-rncp-dedup

Conversation

@rinchen

@rinchen rinchen commented Jul 31, 2026

Copy link
Copy Markdown
Member

Summary

  • Show RMAP publishing coverage as X of Y (amber when partial), and check Network publish only when every eligible interface is discoverable.
  • Dedupe RNCP enable-request modal and dest-share side effects by LXMF message_hash, and rate-limit already-listening auto-share so periodic catch-up cannot spam peers.
  • Lock the RMAP type matrix with tests/docs and cover the RNCP side-effect dedupe path.

Test plan

  • Connection: RMAP status shows X of Y / amber for partial coverage; full coverage is green
  • Network: Publish control checks only when all eligible interfaces are discoverable; uncheck/partial states match expectations
  • Remote: receive an RNCP enable-request once, then trigger LXMF catch-up — modal and dest-share side effects do not re-fire for the same message_hash
  • Already listening when a peer requests enable: auto-share happens at most once per peer within the request-enable cooldown
  • pnpm run test:run for touched RMAP / RNCP tests

Summary by CodeRabbit

  • New Features

    • RMAP publishing supports multiple eligible interfaces with inactive, partial, and full coverage states.
    • Discovery controls show partial publishing and exclude unsupported interfaces.
    • Status displays report discoverable interfaces versus publishing targets.
  • Bug Fixes

    • Prevented duplicate RNCP prompts, destination sharing, and LXMF notifications.
    • Improved compatibility with older peers receiving destination-share replies.
    • Added cooldowns for repeated automatic sharing requests.
  • Documentation

    • Expanded RMAP publishing and troubleshooting guidance, including partial-state remediation.

rinchen added 2 commits July 31, 2026 10:35
Show publishing coverage as X of Y with amber for partial, check Network publish only when every eligible interface is discoverable, and lock the type matrix with tests and docs.
Dedupe enable-modal and dest-share side effects by LXMF message_hash, and
rate-limit already-listening auto-share so periodic catch-up cannot spam peers.
@coderabbitai

coderabbitai Bot commented Jul 31, 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

The PR adds RMAP publishing coverage states, eligible-interface synchronization, and X-of-Y status display. It also adds RNCP/LXMF message deduplication, destination-share compatibility without pending requests, and per-peer auto-share cooldowns.

Changes

RMAP publishing coverage

Layer / File(s) Summary
Publishing state and synchronization
src/renderer/lib/reticulum/reticulumRmapDiscovery.ts, src/renderer/lib/reticulum/reticulumRmapDiscovery.test.ts
RMAP helpers classify eligible interfaces and distinguish inactive, partial, and full publishing. Synchronization uses any active eligible interface.
Eligible-interface controls
src/renderer/components/ReticulumRmapDiscoveryControls.tsx, src/renderer/components/ReticulumRmapDiscoveryControls.test.tsx, src/renderer/components/reticulum/ReticulumInterfacesPanel.test.tsx
Network publishing updates eligible interfaces, excludes TCP and system-managed interfaces, and marks the checkbox indeterminate for partial coverage.
Coverage status and documentation
src/renderer/components/ReticulumRmapConnectionStatus.tsx, src/renderer/components/ReticulumRmapConnectionStatus.test.tsx, docs/reticulum.md, docs/troubleshooting.md, AGENTS.md
Connection status displays discoverable interfaces out of publish targets with gray, amber, or green styling. Documentation describes eligible interfaces and partial publishing.

RNCP/LXMF side-effect deduplication

Layer / File(s) Summary
Message identity and side-effect tracking
src/renderer/lib/rncpLxmfControlSideEffectDedup.ts, src/renderer/lib/rncpLxmfControlSideEffectDedup.test.ts
The new module resolves message hashes, tracks handled effects with expiry and capacity limits, and rate-limits already-enabled auto-sharing per peer.
Runtime and modal integration
src/renderer/runtime/useReticulumRuntime.ts, src/renderer/components/remote/RncpEnableRequestModal.tsx, src/renderer/components/remote/RncpEnableRequestModal.test.tsx
Runtime handling ignores duplicate control messages. The modal retries failed shares and sends an automatic destination share only when the peer cooldown slot is available.
RNCP behavior documentation
docs/troubleshooting.md, AGENTS.md
RNCP guidance documents destination-share application without pending state, message deduplication, and auto-share limits.

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

Sequence Diagram(s)

sequenceDiagram
  participant RNCPPeer
  participant useReticulumRuntime
  participant Deduplication
  participant RncpEnableRequestModal
  RNCPPeer->>useReticulumRuntime: deliver RNCP control message
  useReticulumRuntime->>Deduplication: resolve and reserve message hash
  Deduplication-->>useReticulumRuntime: accept first occurrence
  useReticulumRuntime->>RncpEnableRequestModal: enqueue enable request
  RncpEnableRequestModal->>Deduplication: reserve peer auto-share slot
  Deduplication-->>RncpEnableRequestModal: allow one destination share
  RncpEnableRequestModal->>RNCPPeer: send receive-destination share
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 59.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the two primary changes: RMAP X-of-Y status and RNCP catch-up deduplication.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/reticulum-rmap-status-rncp-dedup

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

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

🤖 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/renderer/components/ReticulumRmapConnectionStatus.test.tsx`:
- Around line 51-86: Add vitest-axe accessibility assertions to both partial and
full publishing tests in ReticulumRmapConnectionStatus: after rendering, hydrate
axe theme colors, obtain the rendered role="status" element, and assert await
axe(status).toHaveNoViolations() while preserving the existing text and class
assertions.

In `@src/renderer/lib/reticulum/reticulumRmapDiscovery.ts`:
- Around line 134-158: Update listReticulumRmapDiscoveryCapable, or the shared
filtering boundary immediately before readRmapAnyPublishing,
readRmapPublishState, and readRmapPublishPartial consume it, to exclude
system-managed rows while retaining user-managed RNode rows. Ensure
system-managed shared-instance rnode entries cannot become publish targets,
affect coverage, or drive synchronization, and add a regression case covering an
enabled system-managed rnode with a serial port.

In `@src/renderer/lib/rncpLxmfControlSideEffectDedup.ts`:
- Around line 60-69: Replace immediate deduplication consumption in
src/renderer/lib/rncpLxmfControlSideEffectDedup.ts:60-69 with reservation,
commit, and release operations that use reservation identity so an old attempt
cannot release a newer reservation. In
src/renderer/runtime/useReticulumRuntime.ts:602-618, release recoverable
destination-share failures and commit successful or terminal invalid-share
outcomes. In src/renderer/components/remote/RncpEnableRequestModal.tsx:120-137,
release the peer cooldown reservation when no destination-share LXMF message is
sent. In src/renderer/components/remote/RncpEnableRequestModal.test.tsx:118-141,
verify a failed initial auto-share permits a later retry for the same peer.
- Around line 76-87: Update tryConsumeRncpAlreadyEnabledAutoShareSlot to prune
entries whose timestamps are outside RNCP_REQUEST_ENABLE_COOLDOWN_MS before
inserting a new peer, then enforce a maximum retained-entry count by removing
older entries when necessary. Preserve the existing cooldown check and
successful slot-consumption behavior while ensuring alreadyEnabledShareAtByPeer
cannot grow without bound.
🪄 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: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: c6826358-67c4-4ab4-a5d8-6720cb15a9d0

📥 Commits

Reviewing files that changed from the base of the PR and between aa01874 and 8d2a5f1.

⛔ Files ignored due to path filters (16)
  • src/renderer/locales/cs/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/de/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/en/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/es/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/fr/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/id/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/it/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/ja/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/ko/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/nl/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/pl/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/pt-BR/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/ru/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/tr/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/uk/translation.json is excluded by !src/renderer/locales/**
  • src/renderer/locales/zh/translation.json is excluded by !src/renderer/locales/**
📒 Files selected for processing (15)
  • AGENTS.md
  • docs/reticulum.md
  • docs/troubleshooting.md
  • src/renderer/components/ReticulumRmapConnectionStatus.test.tsx
  • src/renderer/components/ReticulumRmapConnectionStatus.tsx
  • src/renderer/components/ReticulumRmapDiscoveryControls.test.tsx
  • src/renderer/components/ReticulumRmapDiscoveryControls.tsx
  • src/renderer/components/remote/RncpEnableRequestModal.test.tsx
  • src/renderer/components/remote/RncpEnableRequestModal.tsx
  • src/renderer/components/reticulum/ReticulumInterfacesPanel.test.tsx
  • src/renderer/lib/reticulum/reticulumRmapDiscovery.test.ts
  • src/renderer/lib/reticulum/reticulumRmapDiscovery.ts
  • src/renderer/lib/rncpLxmfControlSideEffectDedup.test.ts
  • src/renderer/lib/rncpLxmfControlSideEffectDedup.ts
  • src/renderer/runtime/useReticulumRuntime.ts

Comment thread src/renderer/components/ReticulumRmapConnectionStatus.test.tsx Outdated
Comment thread src/renderer/lib/reticulum/reticulumRmapDiscovery.ts
Comment thread src/renderer/lib/rncpLxmfControlSideEffectDedup.ts Outdated
Comment thread src/renderer/lib/rncpLxmfControlSideEffectDedup.ts
Exclude system-managed RMAP targets, reserve/commit side-effect dedup on terminal outcomes, bound peer cooldown, and add axe coverage.

@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)
src/renderer/runtime/useReticulumRuntime.ts (1)

594-630: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add direct runtime tests for the RNCP share reservation branch.

Cover commit for success and terminal reasons, and release for retryable failures. Existing tests cover the helpers and apply function separately, not this runtime decision.

🤖 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/renderer/runtime/useReticulumRuntime.ts` around lines 594 - 630, Add
direct runtime tests around the RNCP receive-destination share handling branch
in useReticulumRuntime, covering reservation commit when
applyRncpReceiveDestShareFromLxmf returns ok, no_share, or invalid_sender, and
reservation release for retryable failures. Verify the reservation outcome and
preserve the existing duplicate/early-return behavior when
tryReserveRncpLxmfControlHandled returns no reservation.

Source: Coding guidelines

🤖 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 `@src/renderer/runtime/useReticulumRuntime.ts`:
- Around line 594-630: Add direct runtime tests around the RNCP
receive-destination share handling branch in useReticulumRuntime, covering
reservation commit when applyRncpReceiveDestShareFromLxmf returns ok, no_share,
or invalid_sender, and reservation release for retryable failures. Verify the
reservation outcome and preserve the existing duplicate/early-return behavior
when tryReserveRncpLxmfControlHandled returns no reservation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: dd1e9f6f-1662-4572-a0b3-46b31afe48a9

📥 Commits

Reviewing files that changed from the base of the PR and between 8d2a5f1 and 61e3411.

📒 Files selected for processing (8)
  • src/renderer/components/ReticulumRmapConnectionStatus.test.tsx
  • src/renderer/components/remote/RncpEnableRequestModal.test.tsx
  • src/renderer/components/remote/RncpEnableRequestModal.tsx
  • src/renderer/lib/reticulum/reticulumRmapDiscovery.test.ts
  • src/renderer/lib/reticulum/reticulumRmapDiscovery.ts
  • src/renderer/lib/rncpLxmfControlSideEffectDedup.test.ts
  • src/renderer/lib/rncpLxmfControlSideEffectDedup.ts
  • src/renderer/runtime/useReticulumRuntime.ts

Add useReticulumRuntime tests for terminal apply outcomes committing the
control-hash reservation, upsert_failed releasing for retry, and early
return when no reservation is available.
@rinchen
rinchen merged commit d2a477c into main Jul 31, 2026
12 checks passed
@rinchen
rinchen deleted the feat/reticulum-rmap-status-rncp-dedup branch July 31, 2026 17:18
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.

1 participant