Skip to content

fix: announce before propagation sync and clarify establish stalls - #720

Merged
rinchen merged 3 commits into
mainfrom
fix/propagation-sync-announce-before-establish
Jul 28, 2026
Merged

fix: announce before propagation sync and clarify establish stalls#720
rinchen merged 3 commits into
mainfrom
fix/propagation-sync-announce-before-establish

Conversation

@rinchen

@rinchen rinchen commented Jul 28, 2026

Copy link
Copy Markdown
Member

Summary

  • Debounces an LXMF delivery announce (~30s) before remote Propagation Sync so PNs can return LRPROOF (follow-up to fix: harden Reticulum propagation sync and add PN discovery #718 / tester “unreachable after Announce once worked”).
  • Persists and rehydrates discovered PN public keys; stalls without a proof emit NoLinkProof instead of generic unreachable; dual 60s watchdog no longer overwrites sidecar failure keys.
  • Sync UI hint + docs/troubleshooting updates for reverse-path / Announce now.

Test plan

  • Prefer a discovered remote PN; click Sync without manual Announce — sync should establish more reliably on multi-hop hubs
  • Force a stall (unreachable PN / no reverse path) — toast should mention missing link proof / Announce now, not only “unreachable”
  • Rapid Sync clicks within ~30s — only one LXMF announce (debounce)
  • Cancel mid-sync — still shows cancelled; sidecar establish failure is not replaced by cancelled/timeout
  • CI: sidecar clippy + Vitest green

Summary by CodeRabbit

  • New Features
    • Improved propagation sync flow with debounced LXMF announces and more reliable remote synchronization, including better propagation node identity/key retention.
    • Added clearer UI guidance and localized messaging for “no link proof,” “unknown sync offer,” and remote bidirectional-path requirements.
  • Bug Fixes
    • Fixed propagation sync stall/cancellation handling so progress/state don’t advance incorrectly and last error messages aren’t overwritten.
  • Documentation
    • Updated propagation and troubleshooting guidance with refined retry/timing and log-check instructions.
  • Tests
    • Expanded coverage for debounce behavior, stale-run cancellation safety, and error-to-UI mapping.

Debounce an LXMF delivery announce before remote Sync so PNs can return
LRPROOF, persist discovered PN pubkeys, and map NoLinkProof / watchdog
races instead of a generic unreachable toast.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e90fcb5f-1c75-480a-8ae2-112b997af323

📥 Commits

Reviewing files that changed from the base of the PR and between b5ad09d and 4f8ae80.

📒 Files selected for processing (2)
  • reticulum-sidecar/src/stack/live.rs
  • reticulum-sidecar/src/stack/propagation_bridge.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • reticulum-sidecar/src/stack/propagation_bridge.rs
  • reticulum-sidecar/src/stack/live.rs

📝 Walkthrough

Walkthrough

Propagation sync now persists propagation identities, debounces LXMF announces before establishment, prevents stale run effects, reports NoLinkProof stalls, preserves sidecar errors during renderer cancellation, and adds localized sync guidance.

Changes

Propagation synchronization

Layer / File(s) Summary
Persist and enrich propagation identities
reticulum-sidecar/src/stack/types.rs, reticulum-sidecar/src/stack/persistence.rs, reticulum-sidecar/src/stack/mod.rs, reticulum-sidecar/src/stack/live.rs, src/renderer/runtime/useReticulumRuntime.ts
Propagation rows and discovered entries store optional public-key and identity metadata, preserve it across serialization, and enrich registered or emitted nodes from live discovery.
Debounced announce and establish flow
reticulum-sidecar/src/stack/lxmf_delivery.rs, reticulum-sidecar/src/stack/live.rs, reticulum-sidecar/src/stack/propagation_bridge.rs
Propagation sync rehydrates identities, sends debounced LXMF announces before establishment, records pinning state, and scopes cancellation and progress events to the active sync run.
Renderer timeout and error state handling
src/renderer/lib/reticulum/reticulumPropagationSync.ts, src/renderer/stores/reticulumPropagationStore.ts, src/renderer/components/ReticulumPropagationSection.tsx, src/renderer/locales/*/translation.json, src/renderer/lib/reticulum/reticulumPropagationSync.test.ts, src/renderer/stores/reticulumPropagationStore.test.ts, docs/reticulum.md, docs/troubleshooting.md
Renderer watchdog cancellation uses a timeout reason, preserves existing sidecar failures, maps new offer and establish errors, and displays localized path and failure guidance.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ReticulumPropagationStore
  participant LiveBridge
  participant lxmf_delivery
  participant PropagationNode
  ReticulumPropagationStore->>LiveBridge: start_propagation_sync
  LiveBridge->>LiveBridge: rehydrate persisted PN identity
  LiveBridge->>lxmf_delivery: ensure debounced LXMF announce
  lxmf_delivery->>PropagationNode: send delivery announce
  LiveBridge->>PropagationNode: establish pinned propagation link
  PropagationNode-->>LiveBridge: link proof or NoLinkProof
  LiveBridge-->>ReticulumPropagationStore: sync result or establish error
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% 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 matches the main change: debouncing an announce before propagation sync and improving establish-stall handling.
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
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/propagation-sync-announce-before-establish

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/stores/reticulumPropagationStore.ts (1)

246-268: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Reset sync state when cancellation fails.

cancelSync clears both watchdogs before awaiting proxyPost, but its catch returns without resetting sync or recording the cancellation reason. A failed sidecar cancellation can therefore leave sync.active stuck at true with no watchdog left to recover it.

Run the same finalization logic on both success and failure paths while preserving any sidecar error already present.

Proposed fix
   cancelSync: async (opts) => {
+    const finalizeCancel = () => {
+      set((state) => {
+        const fallback = opts?.reasonKey ?? 'reticulumPropagation.syncCancelled';
+        const existing = state.lastSyncError;
+        const keepSidecar =
+          existing != null &&
+          existing !== 'reticulumPropagation.syncCancelled' &&
+          existing !== 'reticulumPropagation.syncTimedOut';
+        return {
+          sync: { ...RETICULUM_PROPAGATION_SYNC_IDLE },
+          lastSyncError: keepSidecar ? existing : fallback,
+        };
+      });
+    };
     try {
       clearPropagationSyncStallWatchdog();
       await window.electronAPI.reticulum.proxyPost('/api/v1/propagation/sync/cancel', {});
-      set((state) => {
-        // existing finalization block
-      });
+      finalizeCancel();
       return true;
     } catch (e) {
       console.warn('[reticulumPropagationStore] cancel ' + errLikeToLogString(e));
+      finalizeCancel();
       return false;
     }
🤖 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/stores/reticulumPropagationStore.ts` around lines 246 - 268,
Update cancelSync so both successful and failed proxyPost attempts execute the
same finalization that resets sync to RETICULUM_PROPAGATION_SYNC_IDLE and
records the cancellation fallback while preserving an existing sidecar error.
Keep the warning and false return for failures, but move or reuse the set logic
so the catch path cannot leave sync.active stuck.
🤖 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 `@reticulum-sidecar/src/stack/live.rs`:
- Around line 1943-1952: Scope propagation identity pins and watchdog
cancellation to the individual sync run rather than the shared cancellation
flag. Update the sync emitter and its timeout handling around the pinning flow
in the surrounding live-sync implementation to use a per-run cancellation token
or generation, ensuring an older emitter cannot cancel a newer run or invoke
clear_propagation_identity_pins() for it. Add a regression test that triggers a
rapid re-sync and verifies the newer run’s pins remain intact.

In `@reticulum-sidecar/src/stack/mod.rs`:
- Around line 1045-1048: Update the add_propagation_node flow around
register_propagation_node_identity to carry the announce public_key from
discovery, or resolve it before persistence, instead of relying only on the
bounded outbound cache. Ensure pub_key remains available when the announce has
been evicted so the saved propagation node includes public_key and rehydration
can restore it.

In `@src/renderer/locales/ko/translation.json`:
- Around line 3942-3944: Update the syncEstablishNoLinkProof translation to
replace the malformed “네트워크 발표를 → 시도한 다음” recovery instruction with a
grammatical imperative directing users to announce on the network now, then
retry synchronization.

In `@src/renderer/locales/pt-BR/translation.json`:
- Line 3942: Update the syncEstablishNoLinkProof translation in
src/renderer/locales/pt-BR/translation.json at line 3942 and
src/renderer/locales/tr/translation.json at line 3942 so the arrow appears
between the two menu labels, rather than before “Anúncio de Rede” or its Turkish
equivalent; preserve the surrounding localized message.

In `@src/renderer/locales/uk/translation.json`:
- Line 3944: Update the syncEstablishNoLinkProof translation value to replace
the grammatically incorrect “вашій особи” with the correct Ukrainian wording,
such as “вашій ідентичності,” while preserving the rest of the message and its
meaning.

---

Outside diff comments:
In `@src/renderer/stores/reticulumPropagationStore.ts`:
- Around line 246-268: Update cancelSync so both successful and failed proxyPost
attempts execute the same finalization that resets sync to
RETICULUM_PROPAGATION_SYNC_IDLE and records the cancellation fallback while
preserving an existing sidecar error. Keep the warning and false return for
failures, but move or reuse the set logic so the catch path cannot leave
sync.active stuck.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 41023140-4ddd-4e30-9229-4684025024b3

📥 Commits

Reviewing files that changed from the base of the PR and between 1a9957b and 0bfcf8e.

📒 Files selected for processing (29)
  • docs/reticulum.md
  • docs/troubleshooting.md
  • reticulum-sidecar/src/stack/live.rs
  • reticulum-sidecar/src/stack/lxmf_delivery.rs
  • reticulum-sidecar/src/stack/mod.rs
  • reticulum-sidecar/src/stack/persistence.rs
  • reticulum-sidecar/src/stack/propagation_bridge.rs
  • reticulum-sidecar/src/stack/types.rs
  • src/renderer/components/ReticulumPropagationSection.tsx
  • src/renderer/lib/reticulum/reticulumPropagationSync.test.ts
  • src/renderer/lib/reticulum/reticulumPropagationSync.ts
  • src/renderer/locales/cs/translation.json
  • src/renderer/locales/de/translation.json
  • src/renderer/locales/en/translation.json
  • src/renderer/locales/es/translation.json
  • src/renderer/locales/fr/translation.json
  • src/renderer/locales/id/translation.json
  • src/renderer/locales/it/translation.json
  • src/renderer/locales/ja/translation.json
  • src/renderer/locales/ko/translation.json
  • src/renderer/locales/nl/translation.json
  • src/renderer/locales/pl/translation.json
  • src/renderer/locales/pt-BR/translation.json
  • src/renderer/locales/ru/translation.json
  • src/renderer/locales/tr/translation.json
  • src/renderer/locales/uk/translation.json
  • src/renderer/locales/zh/translation.json
  • src/renderer/stores/reticulumPropagationStore.test.ts
  • src/renderer/stores/reticulumPropagationStore.ts

Comment thread reticulum-sidecar/src/stack/live.rs
Comment thread reticulum-sidecar/src/stack/mod.rs Outdated
Comment thread src/renderer/locales/ko/translation.json Outdated
Comment thread src/renderer/locales/pt-BR/translation.json Outdated
Comment thread src/renderer/locales/uk/translation.json Outdated
Scope sync emitters per run so stale cancel/pin clears cannot race a
new sync, persist discovered PN public keys through add, use <output>
for the establish hint, and finalize cancelSync on proxy failure.

@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

🤖 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 `@reticulum-sidecar/src/stack/propagation_bridge.rs`:
- Around line 174-183: Make generation validation and terminal side effects
atomic in the propagation bridge. Update the lifecycle around is_current,
clear_pins, and the related cancellation, pin cleanup, and event-send paths at
the referenced sections to use a shared lifecycle lock or re-check generation
while holding each affected resource lock, preventing an old emitter from acting
on a newer run. Preserve current-run behavior while rejecting stale side effects
under concurrent run replacement.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8b42d9f1-6583-4c04-ac62-e56bb75cf9c3

📥 Commits

Reviewing files that changed from the base of the PR and between 0bfcf8e and b5ad09d.

📒 Files selected for processing (12)
  • reticulum-sidecar/src/stack/live.rs
  • reticulum-sidecar/src/stack/mod.rs
  • reticulum-sidecar/src/stack/propagation_bridge.rs
  • reticulum-sidecar/src/stack/types.rs
  • src/renderer/components/ReticulumPropagationSection.tsx
  • src/renderer/locales/ko/translation.json
  • src/renderer/locales/pt-BR/translation.json
  • src/renderer/locales/tr/translation.json
  • src/renderer/locales/uk/translation.json
  • src/renderer/runtime/useReticulumRuntime.ts
  • src/renderer/stores/reticulumPropagationStore.test.ts
  • src/renderer/stores/reticulumPropagationStore.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • src/renderer/components/ReticulumPropagationSection.tsx
  • src/renderer/stores/reticulumPropagationStore.test.ts
  • reticulum-sidecar/src/stack/mod.rs
  • src/renderer/locales/uk/translation.json
  • reticulum-sidecar/src/stack/types.rs
  • src/renderer/locales/tr/translation.json
  • src/renderer/locales/pt-BR/translation.json
  • src/renderer/locales/ko/translation.json
  • reticulum-sidecar/src/stack/live.rs

Comment thread reticulum-sidecar/src/stack/propagation_bridge.rs Outdated
Hold a shared lifecycle lock around run-id replacement and cancel/pin/event
actions so a stale emitter cannot act on a newer sync run.
@sonarqubecloud

Copy link
Copy Markdown

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