Skip to content

Conversation

@alltheseas
Copy link

@alltheseas alltheseas commented Oct 28, 2025

Warning

Hallucinations may be present, or all encompassing.

Findings

  1. src/whitenoise/groups.rs:322 — Severity: High;
    Likelihood: High.
    Each add/ remove/update path calls mdk.merge_pending_commit before publish_event_to
    confirms relay acceptance. If the publish fails or a competing commit
    lands first, the local store advances epochs that the rest of the group never
    sees, leading to irrecoverable state forks and message loss until manual
    recovery.

  2. src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs:73 —
    Severity: Medium; Likelihood: Medium.
    The client only republishes a fresh
    KeyPackage when it just deleted the old one. In cases where the relay
    already dropped the event (expiry, manual cleanup, last-resort reuse) the
    branch skips rotation, leaving members without any discoverable
    KeyPackage and preventing future invitations..

Problem Statement

  1. Group membership flows were advancing the local MLS epoch immediately after staging a commit, before confirming relay acceptance. If a publish failed or a competing commit landed first, our local state jumped ahead of the rest of the group, creating forks that required manual recovery.

  2. Separately, welcome processing only rotated key packages when it had just deleted the old event; if relays had already dropped the key package, members were left without any discoverable package and could not receive new invites.

Proposed Solution Overview

  • In whitenoise::groups, wait until publish_event_to reports at least one successful relay before merging pending commits; surface relay failures as
    explicit errors instead of advancing state.
  • In handle_giftwrap, always republish a fresh key package after processing a welcome, treating dead/missing key packages as a rotation trigger rather
    than a no-op.
  • Extend NostrManager to flag total publish rejection and propagate that error upward, allowing the group workflow to respond appropriately.

Tests

  • I could not get all the tests to run
  • I could not get docker/local relay to run
  • cargo test (fails for integration-style cases that require local relays on localhost:8080/7777; compile/unit tests pass and blocker tests exercised manually where possible).

Benefits

  • Prevents irreversible MLS state divergence when relays reject or drop commits.
  • Ensures members always regain a reachable key package after processing welcomes, even if relays wiped the previous one.
  • Improves observability by distinguishing between successful publishes and total denials, making follow-up retries or UI messaging practical.

Tradeoffs

  • Callers now see an error when every relay rejects the commit, so API consumers must be prepared to handle and retry.
  • A successful publish requires at least one relay acknowledgement; single-relay setups that are temporarily offline will now block the merge rather than allowing optimistic advancement.

What Happens If Not Implemented

-Groups will continue to fork silently whenever a publish fails mid-flight, leading to message loss until someone manually resets the group.

  • Members who lose their key package on relays will stay invisible to new invites, effectively locking them out of future group additions.

Summary by CodeRabbit

  • New Features

    • Added an automated Docker Engine installer with version pinning, channel selection, mirror options, and distro detection.
  • Bug Fixes

    • Improved publication error handling to surface full rejection when all relays decline an event.
    • Ensure group updates publish to relays before merging local state, reducing desyncs.
    • Republish missing key packages on welcome processing to restore account state when absent.
  • Tests

    • Added/adjusted tests to validate new publish/reject and republish behaviors.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 28, 2025

Walkthrough

Adds a cross-distro Docker installer script, tightens Nostr publish error semantics to fail when all relays reject, changes group operations to publish-before-local-merge, and adjusts key-package welcome handling to unconditionally republish missing key packages with refined error branches.

Changes

Cohort / File(s) Summary
Docker Installation Script
get-docker.sh
New executable shell installer that detects distro/WSL/macos, configures repos, supports --channel/--version/--mirror/--setup-repo/--dry-run, pins versions, and installs Docker packages across Debian/Ubuntu, RHEL/CentOS/Fedora, and SLES.
Nostr Manager Errors
src/nostr_manager/mod.rs
Adds PublishRejected { event_id: EventId, attempted: usize } to NostrManagerError to represent all-relay rejection of a published event.
Publisher Logic & Tests
src/nostr_manager/publisher.rs
Treats zero-success publish as an error returning PublishRejected, captures event_id for logging, adjusts success/rejection tracking, and updates tests to expect the new semantics.
Giftwrap Welcome Handling
src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs
Replaces boolean-based delete handling with Result matching, logs and branches explicitly (including AccountMissingKeyPackageRelays), always republishes key package when needed, and adds/adjusts tests with relay-availability checks.
Group Evolution Flow
src/whitenoise/groups.rs
Refactors add/remove/update group functions to publish evolution events first, await relay acknowledgments, then merge pending commits locally; adds explicit error/warning handling for full or partial publish failures.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant GroupMgr as Group Manager
    participant Publisher as Publisher
    participant Relays
    participant LocalState as Local State

    rect rgb(220,240,255)
    Note over Client,LocalState: Old Flow — immediate local merge
    Client->>GroupMgr: request change (add/remove/update)
    GroupMgr->>LocalState: Merge pending commit locally
    GroupMgr->>Publisher: publish_event()
    Publisher->>Relays: send event
    Relays-->>Publisher: ack/reject
    end

    rect rgb(240,255,240)
    Note over Client,LocalState: New Flow — publish-then-merge
    Client->>GroupMgr: request change (add/remove/update)
    GroupMgr->>Publisher: publish_event()
    Publisher->>Relays: send event
    Relays-->>Publisher: ack results
    alt >0 acks
        Publisher-->>GroupMgr: Ok (acks)
        GroupMgr->>LocalState: Merge pending commit
        GroupMgr-->>Client: Success
    else 0 acks
        Publisher-->>GroupMgr: Err (PublishRejected)
        GroupMgr-->>Client: Error
    end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas requiring extra attention:
    • get-docker.sh — long, multi-distro shell logic: shell-safety, edge-case handling, and repository/GPG steps.
    • src/nostr_manager/publisher.rs and src/nostr_manager/mod.rs — new error variant and changed publish semantics; verify all callers/tests handle PublishRejected.
    • src/whitenoise/groups.rs — publish-then-merge changes affect local-state consistency; review rollback/error paths.
    • src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs — verify the new Result branches and test relay-availability gating.

Possibly related PRs

Suggested reviewers

  • delcin-raj
  • jgmontoya

Poem

🐰
I hopped and built a tiny script,
Pushed events until relays quipped,
Publish first, then merge at last,
Key packages reborn from past,
A rabbit cheers — the changes shipped! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Prevent MLS state forks and republish missing key packages" directly addresses the two main correctness issues described in the PR objectives. It specifically references preventing MLS state forks (the critical issue in src/whitenoise/groups.rs where pending commits were merged before relay confirmation) and republishing missing key packages (the secondary issue in src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs). The title is concise, specific, and clear enough that a teammate scanning history would understand the primary changes without ambiguity. While the raw_summary includes an unrelated get-docker.sh file addition, the stated PR objectives focus entirely on the MLS-related fixes, which the title accurately captures.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8d28436 and 67e5f2a.

📒 Files selected for processing (5)
  • get-docker.sh (1 hunks)
  • src/nostr_manager/mod.rs (1 hunks)
  • src/nostr_manager/publisher.rs (3 hunks)
  • src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs (4 hunks)
  • src/whitenoise/groups.rs (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/nostr_manager/mod.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (.cursor/rules/rust-code-style.mdc)

**/*.rs: Write all trait bounds in a where clause for functions and impl blocks
Prefer using Self when referring to the implementing type (including return types and enum variant matches)
For public types in libraries, derive Debug, Clone, Copy, PartialEq, Eq, and Hash (in this order) when possible
Derive Default only when a reasonable default value exists
Use full paths for tracing macros (tracing::!(...)) instead of importing macro names
Prefer .to_string() or .to_owned() for &str -> String conversion over .into() or String::from
Order imports: (1) core/alloc/std, (2) external crates, (3) current sub-modules (mod x;), (4) internal crate modules (use crate::, super::, self::)
When implementing fmt traits, import core::fmt and use fmt::Display, fmt::Formatter, etc.
After declaring mod x;, import sub-items via self::x::Y instead of x::Y
Avoid if let ... { } else { } in favor of match when both branches do work
Use if let ... { } when the alternative match arm is intentionally empty
Avoid inline sub-modules (mod x { ... }); prefer a separate file x.rs with mod x; (except tests and benches)
For tests, prefer inline #[cfg(test)] mod tests { ... } and avoid mod tests;
For benches, prefer inline #[cfg(bench)] mod benches { ... } and avoid mod benches;

Files:

  • src/nostr_manager/publisher.rs
  • src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs
  • src/whitenoise/groups.rs
src/whitenoise/{event_processor/event_handlers/handle_mls_message.rs,key_packages.rs,groups.rs,welcomes.rs}

📄 CodeRabbit inference engine (.cursor/rules/mls-protocol-docs.mdc)

src/whitenoise/{event_processor/event_handlers/handle_mls_message.rs,key_packages.rs,groups.rs,welcomes.rs}: Use the existing rust-nostr MLS crate APIs instead of reimplementing cryptographic or MLS primitives
Preserve forward secrecy in MLS operations (ephemeral keys, proper secret updates)
Ensure post-compromise security through correct epoch transitions and secret updates
Authenticate group membership for all MLS operations (e.g., validating credentials and proposals)
Maintain message ordering and group state consistency across epochs
Implement and verify key rotation procedures as specified by MLS

Files:

  • src/whitenoise/groups.rs
🧠 Learnings (5)
📚 Learning: 2025-08-11T10:25:55.436Z
Learnt from: jgmontoya
PR: parres-hq/whitenoise#310
File: src/whitenoise/accounts/mod.rs:669-692
Timestamp: 2025-08-11T10:25:55.436Z
Learning: In the Whitenoise codebase, the `NostrManager::publish_event_builder_with_signer` method automatically ensures relay connectivity by calling `self.add_relays()` before publishing events. This means explicit relay connectivity checks are not needed before calling publishing methods that use this function.

Applied to files:

  • src/nostr_manager/publisher.rs
📚 Learning: 2025-09-11T13:04:33.349Z
Learnt from: erskingardner
PR: parres-hq/whitenoise#354
File: src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs:0-0
Timestamp: 2025-09-11T13:04:33.349Z
Learning: In the whitenoise project, when processing MLS Welcome messages in handle_giftwrap.rs, the code should only publish a replacement key package if the deletion of the used key package was successful (deleted == true). The conditional publishing behavior is intentional and should not be changed to always publish regardless of deletion success.

Applied to files:

  • src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs
📚 Learning: 2025-09-29T10:45:56.426Z
Learnt from: CR
PR: parres-hq/whitenoise#0
File: .cursor/rules/mls-protocol-docs.mdc:0-0
Timestamp: 2025-09-29T10:45:56.426Z
Learning: Applies to src/whitenoise/{event_processor/event_handlers/handle_mls_message.rs,key_packages.rs,groups.rs,welcomes.rs} : Implement and verify key rotation procedures as specified by MLS

Applied to files:

  • src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs
📚 Learning: 2025-08-23T16:27:41.511Z
Learnt from: jgmontoya
PR: parres-hq/whitenoise#324
File: src/integration_tests/test_cases/subscription_processing/publish_metadata_update.rs:42-45
Timestamp: 2025-08-23T16:27:41.511Z
Learning: In Whitenoise integration tests, using `unwrap()` on `test_client.add_relay()` for dev relay connections is acceptable since these are controlled test environments where failing fast is preferred over complex error handling.

Applied to files:

  • src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs
📚 Learning: 2025-09-29T10:45:56.426Z
Learnt from: CR
PR: parres-hq/whitenoise#0
File: .cursor/rules/mls-protocol-docs.mdc:0-0
Timestamp: 2025-09-29T10:45:56.426Z
Learning: Applies to src/whitenoise/{event_processor/event_handlers/handle_mls_message.rs,key_packages.rs,groups.rs,welcomes.rs} : Maintain message ordering and group state consistency across epochs

Applied to files:

  • src/whitenoise/groups.rs
🧬 Code graph analysis (2)
src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs (4)
src/whitenoise/accounts.rs (1)
  • relays (98-106)
src/whitenoise/database/users.rs (1)
  • relays (166-198)
src/whitenoise/mod.rs (2)
  • create_mock_whitenoise (646-708)
  • setup_multiple_test_accounts (817-844)
src/whitenoise/relays.rs (1)
  • urls (105-110)
src/whitenoise/groups.rs (1)
src/whitenoise/accounts.rs (2)
  • create_mdk (263-270)
  • create_mdk (909-911)
🔇 Additional comments (10)
src/nostr_manager/publisher.rs (3)

195-209: Correctly implements all-relays-rejected error handling.

The logic appropriately:

  • Captures event_id early for diagnostic logging
  • Returns PublishRejected when no relays accept the event (line 198-209)
  • Only tracks successfully published events (line 212)

This aligns with the PR objective to surface total publish failures as explicit errors and prevents local state advancement when all relays reject.


527-534: Test correctly updated for new error semantics.

The test now expects an error when publishing to unreachable relays, matching the new behavior where success.is_empty() returns PublishRejected instead of Ok with empty successes.


573-576: Good defensive assertion in success test.

Verifying !output.success.is_empty() ensures the test validates that at least one relay acknowledged the event in the success path.

src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs (4)

73-102: Match pattern correctly implements refined error handling.

The match expression appropriately handles all deletion outcomes:

  • Early return only on critical errors (AccountMissingKeyPackageRelays)
  • Logs warnings for non-critical failures and continues
  • This enables unconditional key package republishing (lines 110-114)

The change aligns with the PR objective to "always republish a fresh KeyPackage after processing a welcome, treating missing/dead key packages as a rotation trigger."

Note: This intentionally diverges from past behavior per retrieved learning, which only republished when deletion succeeded.

Based on PR objectives.


110-114: Unconditional key package republishing addresses PR objective.

Publishing a fresh key package after every welcome processing ensures key package discoverability and prevents future invitation failures when relays drop events. This directly addresses the second correctness issue described in the PR objectives.


126-147: Useful test helper for relay availability checks.

The relays_running helper appropriately checks TCP connectivity to test relays before running tests, allowing graceful skips when infrastructure is unavailable. The 200ms timeout is reasonable for local testing.


249-317: Excellent test coverage for key package republication.

The test validates the core fix by:

  1. Explicitly deleting the existing key package from relays
  2. Verifying it's missing before processing the welcome
  3. Confirming it's republished after processing the welcome

This directly tests the PR objective: "always republish a fresh KeyPackage after processing a welcome."

src/whitenoise/groups.rs (3)

318-367: Publish-then-merge pattern correctly prevents MLS state forks.

The logic properly implements the publish-before-local-merge flow:

  1. Creates pending commit (line 320)
  2. Publishes to relays and waits for acknowledgment (line 336-339)
  3. Errors only when all relays reject (lines 341-350)
  4. Logs warnings for partial failures (lines 351-363)
  5. Merges locally only after ≥1 relay acknowledges (line 367)

This addresses the first PR objective: preventing local state from advancing epochs when publish fails, which would cause irrecoverable state forks.


436-471: Removal flow correctly mirrors add-members publish-then-merge pattern.

The logic is consistent with add_members_to_group:

  • Publishes evolution event before local merge (lines 441-444)
  • Returns error only when all relays reject (lines 446-455)
  • Logs warnings for partial failures (lines 456-468)
  • Merges pending commit only after successful publish (line 471)

This prevents state forks during member removal operations.


489-524: Group data update follows consistent publish-then-merge pattern.

The update flow maintains the same correctness guarantees as member operations:

  • Evolution event published first (lines 494-497)
  • Hard error when all relays reject (lines 499-508)
  • Warning for partial rejections (lines 509-521)
  • Local merge only after successful publish (line 524)

All three group evolution operations (add/remove/update) now consistently prevent MLS state forks.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (4)
src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs (2)

126-147: Make relay probe more robust to avoid false skips

Current host/port connect with 200ms timeout is brittle. Prefer fixed socket list (127.0.0.1:8080, 127.0.0.1:7777) and a slightly longer timeout or short retry.

-    async fn relays_running() -> bool {
-        let relay_urls = ["ws://localhost:8080", "ws://localhost:7777"];
-        for relay in relay_urls {
-            if let Ok(url) = RelayUrl::parse(relay) {
-                let host = url.host();
-                let port = url.port();
-                let addr = format!("{}:{}", host, port);
-                if tokio::time::timeout(
-                    Duration::from_millis(200),
-                    tokio::net::TcpStream::connect(&addr),
-                )
-                .await
-                .is_err()
-                {
-                    return false;
-                }
-            } else {
-                return false;
-            }
-        }
-        true
-    }
+    async fn relays_running() -> bool {
+        let sockets = ["127.0.0.1:8080", "127.0.0.1:7777"];
+        for addr in sockets {
+            if tokio::time::timeout(
+                Duration::from_millis(400),
+                tokio::net::TcpStream::connect(addr),
+            )
+            .await
+            .is_err()
+            {
+                return false;
+            }
+        }
+        true
+    }

286-288: Avoid fixed short sleep; poll with backoff to reduce flakiness

50ms may be insufficient for deletions to propagate. Poll fetch with a brief timeout/backoff instead of blind sleep.

-            // Give relays a moment to apply the deletion before we proceed
-            sleep(Duration::from_millis(50)).await;
+            // Wait until deletion is observed or timeout
+            let deadline = std::time::Instant::now() + Duration::from_secs(2);
+            loop {
+                if std::time::Instant::now() >= deadline { break; }
+                if whitenoise
+                    .nostr
+                    .fetch_user_key_package(member_account.pubkey, &relays)
+                    .await
+                    .unwrap()
+                    .is_none()
+                {
+                    break;
+                }
+                sleep(Duration::from_millis(100)).await;
+            }
src/nostr_manager/mod.rs (1)

50-52: PublishRejected variant looks good; consider adding relay context for debuggability

Optional: include attempted relay URLs (Vec) in the error to aid logs/upstream handling.

src/nostr_manager/publisher.rs (1)

234-257: Unify error semantics for builder-based publishes (metadata/relay list/etc.)

If all relays reject, return PublishRejected here too for parity with publish_event_to.

     async fn publish_event_builder_with_signer(
         &self,
         event_builder: EventBuilder,
         relays: &[RelayUrl],
         signer: impl NostrSigner + 'static,
     ) -> Result<Output<EventId>> {
@@
-        // Track the published event if we have a successful result (best-effort)
-        if !result.success.is_empty() {
+        // If no relay accepted, surface explicit rejection
+        if result.success.is_empty() {
+            let event_id = *result.id();
+            tracing::warn!(
+                target: "whitenoise::nostr_manager::publish_event_builder_with_signer",
+                "Event {} was rejected by all relays: attempted {} relays",
+                event_id.to_hex(),
+                relays.len()
+            );
+            return Err(NostrManagerError::PublishRejected {
+                event_id,
+                attempted: relays.len(),
+            });
+        }
+
+        // Track the published event (best-effort)
+        if !result.success.is_empty() {
             self.event_tracker
                 .track_published_event(result.id(), &pubkey)
                 .await
                 .map_err(|e| NostrManagerError::FailedToTrackPublishedEvent(e.to_string()))?;
         }

Please add a small test mirroring test_publish_event_to_unreachable_relays for metadata (builder path) to assert PublishRejected on unreachable relays.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51aa523 and 8d28436.

📒 Files selected for processing (5)
  • get-docker.sh (1 hunks)
  • src/nostr_manager/mod.rs (1 hunks)
  • src/nostr_manager/publisher.rs (3 hunks)
  • src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs (4 hunks)
  • src/whitenoise/groups.rs (5 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (.cursor/rules/rust-code-style.mdc)

**/*.rs: Write all trait bounds in a where clause for functions and impl blocks
Prefer using Self when referring to the implementing type (including return types and enum variant matches)
For public types in libraries, derive Debug, Clone, Copy, PartialEq, Eq, and Hash (in this order) when possible
Derive Default only when a reasonable default value exists
Use full paths for tracing macros (tracing::!(...)) instead of importing macro names
Prefer .to_string() or .to_owned() for &str -> String conversion over .into() or String::from
Order imports: (1) core/alloc/std, (2) external crates, (3) current sub-modules (mod x;), (4) internal crate modules (use crate::, super::, self::)
When implementing fmt traits, import core::fmt and use fmt::Display, fmt::Formatter, etc.
After declaring mod x;, import sub-items via self::x::Y instead of x::Y
Avoid if let ... { } else { } in favor of match when both branches do work
Use if let ... { } when the alternative match arm is intentionally empty
Avoid inline sub-modules (mod x { ... }); prefer a separate file x.rs with mod x; (except tests and benches)
For tests, prefer inline #[cfg(test)] mod tests { ... } and avoid mod tests;
For benches, prefer inline #[cfg(bench)] mod benches { ... } and avoid mod benches;

Files:

  • src/nostr_manager/mod.rs
  • src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs
  • src/whitenoise/groups.rs
  • src/nostr_manager/publisher.rs
src/whitenoise/{event_processor/event_handlers/handle_mls_message.rs,key_packages.rs,groups.rs,welcomes.rs}

📄 CodeRabbit inference engine (.cursor/rules/mls-protocol-docs.mdc)

src/whitenoise/{event_processor/event_handlers/handle_mls_message.rs,key_packages.rs,groups.rs,welcomes.rs}: Use the existing rust-nostr MLS crate APIs instead of reimplementing cryptographic or MLS primitives
Preserve forward secrecy in MLS operations (ephemeral keys, proper secret updates)
Ensure post-compromise security through correct epoch transitions and secret updates
Authenticate group membership for all MLS operations (e.g., validating credentials and proposals)
Maintain message ordering and group state consistency across epochs
Implement and verify key rotation procedures as specified by MLS

Files:

  • src/whitenoise/groups.rs
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
PR: parres-hq/whitenoise#0
File: .cursor/rules/mls-protocol-docs.mdc:0-0
Timestamp: 2025-09-29T10:45:56.426Z
Learning: Applies to src/whitenoise/{event_processor/event_handlers/handle_mls_message.rs,key_packages.rs,groups.rs,welcomes.rs} : Preserve forward secrecy in MLS operations (ephemeral keys, proper secret updates)
📚 Learning: 2025-09-11T13:04:33.349Z
Learnt from: erskingardner
PR: parres-hq/whitenoise#354
File: src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs:0-0
Timestamp: 2025-09-11T13:04:33.349Z
Learning: In the whitenoise project, when processing MLS Welcome messages in handle_giftwrap.rs, the code should only publish a replacement key package if the deletion of the used key package was successful (deleted == true). The conditional publishing behavior is intentional and should not be changed to always publish regardless of deletion success.

Applied to files:

  • src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs
📚 Learning: 2025-09-29T10:45:56.426Z
Learnt from: CR
PR: parres-hq/whitenoise#0
File: .cursor/rules/mls-protocol-docs.mdc:0-0
Timestamp: 2025-09-29T10:45:56.426Z
Learning: Applies to src/whitenoise/{event_processor/event_handlers/handle_mls_message.rs,key_packages.rs,groups.rs,welcomes.rs} : Implement and verify key rotation procedures as specified by MLS

Applied to files:

  • src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs
📚 Learning: 2025-08-23T16:27:41.511Z
Learnt from: jgmontoya
PR: parres-hq/whitenoise#324
File: src/integration_tests/test_cases/subscription_processing/publish_metadata_update.rs:42-45
Timestamp: 2025-08-23T16:27:41.511Z
Learning: In Whitenoise integration tests, using `unwrap()` on `test_client.add_relay()` for dev relay connections is acceptable since these are controlled test environments where failing fast is preferred over complex error handling.

Applied to files:

  • src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs
📚 Learning: 2025-09-29T10:45:56.426Z
Learnt from: CR
PR: parres-hq/whitenoise#0
File: .cursor/rules/mls-protocol-docs.mdc:0-0
Timestamp: 2025-09-29T10:45:56.426Z
Learning: Applies to src/whitenoise/{event_processor/event_handlers/handle_mls_message.rs,key_packages.rs,groups.rs,welcomes.rs} : Maintain message ordering and group state consistency across epochs

Applied to files:

  • src/whitenoise/groups.rs
📚 Learning: 2025-08-11T10:25:55.436Z
Learnt from: jgmontoya
PR: parres-hq/whitenoise#310
File: src/whitenoise/accounts/mod.rs:669-692
Timestamp: 2025-08-11T10:25:55.436Z
Learning: In the Whitenoise codebase, the `NostrManager::publish_event_builder_with_signer` method automatically ensures relay connectivity by calling `self.add_relays()` before publishing events. This means explicit relay connectivity checks are not needed before calling publishing methods that use this function.

Applied to files:

  • src/nostr_manager/publisher.rs
🧬 Code graph analysis (2)
src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs (4)
src/whitenoise/accounts.rs (1)
  • relays (98-106)
src/whitenoise/database/users.rs (1)
  • relays (166-198)
src/whitenoise/mod.rs (2)
  • create_mock_whitenoise (646-708)
  • setup_multiple_test_accounts (817-844)
src/whitenoise/relays.rs (1)
  • urls (105-110)
src/whitenoise/groups.rs (1)
src/whitenoise/accounts.rs (2)
  • create_mdk (263-270)
  • create_mdk (909-911)
🔇 Additional comments (6)
get-docker.sh (4)

174-256: Helper functions are well-implemented.

The version comparison, environment detection, and utility functions are defensive, properly quoted, and handle edge cases like CalVer versions and missing values with fallbacks.


258-378: Distribution detection and forked distro mapping are solid.

Proper error handling with set +e/set -e, safe variable usage, and comprehensive codename mapping for Debian versions. The call site ensures variables are initialized before use.


540-579: Debian/Ubuntu version-conditional package selection is correct.

Version pinning via apt-cache madison is the standard approach, and the conditional package installation based on version gates (18.09 for cli, 20.10 for compose-plugin, etc.) is appropriate. Proper escaping of regex pattern at line 546.


1-87: Note: This file appears orthogonal to the stated PR objectives.

The PR description focuses on MLS state fork prevention and key-package handling (src/whitenoise/groups.rs, handle_giftwrap.rs), but this is a Docker installation utility script. Verify that this file is intentionally included in this PR or if file selection was incorrect. If intentional, document the relationship in the PR description.

src/whitenoise/event_processor/event_handlers/handle_giftwrap.rs (1)

72-102: Unconditional republish alters prior contract — confirm policy change

Always republishing a key package after welcome is a behavioral change from the intentional “only if deletion succeeded” rule. If this supersedes the earlier guidance, please confirm and note in CHANGELOG/migration so API consumers expect potential PublishRejected errors from republish. Based on learnings.

Also applies to: 104-115

src/nostr_manager/publisher.rs (1)

195-209: Correct: return error when all relays reject an already-signed event

This matches PR intent and prevents silent “success with zero ACKs.”

DEFAULT_REPO_FILE="docker-ce.repo"
if [ -z "$REPO_FILE" ]; then
REPO_FILE="$DEFAULT_REPO_FILE"
# Automatically default to a staging repo fora
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typo in comment.

Line 112 has a typo: "fora" should be "for a".

-	# Automatically default to a staging repo fora
-	# a staging download url (download-stage.docker.com)
+	# Automatically default to a staging repo for
+	# a staging download url (download-stage.docker.com)
🤖 Prompt for AI Agents
In get-docker.sh around line 112, the comment contains a typo ("fora"); update
the comment to read "for a" so the line becomes a clear English phrase ("#
Automatically default to a staging repo for a"). Ensure spacing and punctuation
remain consistent with surrounding comments.

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