Skip to content

Conversation

@insipx
Copy link
Contributor

@insipx insipx commented Dec 10, 2025

closes #2790

@insipx
Copy link
Contributor Author

insipx commented Dec 10, 2025

@insipx insipx mentioned this pull request Dec 10, 2025
@claude
Copy link

claude bot commented Dec 10, 2025

Claude finished @insipx's task —— View job


Code Review Complete

Review Date: December 15, 2025 20:51 UTC

I've reviewed the d14n-ordered stream implementation. The overall design is solid, introducing offline ordering with orphan icing. Most issues have been identified by macroscopeapp. Here are additional high-priority concerns not already covered:

Critical Issues

1. Infinite Loop Risk in resolve_children_inner (Already noted by macroscopeapp)
xmtp_api_d14n/src/protocol/in_memory_cursor_store.rs:138-165

The recursive implementation lacks cycle detection. While macroscopeapp flagged this, I want to emphasize the severity: if two envelopes form a dependency cycle (A depends on B, B depends on A), this will recurse indefinitely until stack overflow.

2. Missing Test Coverage for OrderedStream
xmtp_api_d14n/src/queries/stream/ordered.rs:74-104

The new OrderedStream has zero direct unit tests. Codecov shows 82.92% coverage, meaning 7 lines are untested. Critical paths missing coverage:

  • Error propagation from OrderedStreamError (lines 34-50)
  • Stream termination with orphaned envelopes
  • Multiple batches with mixed resolvable/unresolvable dependencies

Recommendation: Add tests for:

#[xmtp_common::test]
async fn test_ordered_stream_with_missing_dependencies()
#[xmtp_common::test]  
async fn test_ordered_stream_error_propagation()

High-Priority Issues

3. Incorrect is_retryable() Implementation (Macroscopeapp's latest finding is correct)
xmtp_api_d14n/src/queries/stream/ordered.rs:40-44

impl RetryableError for OrderedStreamError {
    fn is_retryable(&self) -> bool {
        false  // ❌ Always returns false
    }
}

This breaks retry logic for transient ResolutionErrors. Macroscopeapp's suggested fix is correct:

matches!(self, OrderedStreamError::Resolver(err) if err.is_retryable())

4. Error Type Semantics
xmtp_api_d14n/src/queries/stream/ordered.rs:26-32

The comment says "this is an error which should never occur, and if it does is a bug in libxmtp", but the code treats it as a regular error. If this truly represents an invariant violation:

  • Consider using panic! or unreachable! for unrecoverable cases
  • Or update the comment to reflect actual error semantics (transient ordering failures)

Performance Considerations

5. Cloning TopicCursor on Every Poll
xmtp_api_d14n/src/queries/stream/ordered.rs:95

.topic_cursor(self.topic_cursor.clone())  // HashMap clone on every stream item

TopicCursor is a HashMap<Topic, GlobalCursor>. Cloning on every stream poll could be expensive with many topics. Consider:

  • Using Arc<RwLock<TopicCursor>> if mutations are rare
  • Or passing by reference and mutating in-place (requires API redesign)

6. Memory Swap for Cursor Update
xmtp_api_d14n/src/queries/stream/ordered.rs:99-101

let (envelopes, mut new_cursor) = ordering.into_parts();
let this = self.as_mut().project();
std::mem::swap(this.topic_cursor, &mut new_cursor);

This is correct but slightly awkward. Direct assignment would be clearer:

*this.topic_cursor = new_cursor;

Code Quality

7. TypedNoopResolver Documentation
xmtp_api_d14n/src/protocol/traits/dependency_resolution.rs:69-97

The new TypedNoopResolver<T> lacks documentation. Add:

/// A typed no-op resolver that returns an empty resolution result.
/// Used in streaming contexts where dependencies are expected to arrive
/// in the stream itself rather than being actively fetched.

Security

No security concerns identified. The implementation correctly:

  • Validates dependencies before processing
  • Handles malformed envelopes via EnvelopeError
  • Ices orphans rather than dropping them

Test Coverage Summary

From codecov report:

  • ordered.rs: 82.92% (7 lines missing) - needs stream-level tests
  • dependency_resolution.rs: 71.42% (2 lines missing) - TypedNoopResolver partially tested
  • traits.rs: 0% (3 lines missing) - likely just type definitions

Recommendations Priority

  1. MUST FIX: Cycle detection in resolve_children_inner (macroscopeapp's finding)
  2. MUST FIX: is_retryable() implementation (macroscopeapp's finding)
  3. SHOULD ADD: Direct unit tests for OrderedStream
  4. CONSIDER: Performance optimization for cursor cloning in hot path

Overall this is a well-structured implementation that fits cleanly into the existing ordering architecture. The main gaps are in test coverage and the two critical issues flagged by macroscopeapp.

@insipx insipx force-pushed the insipx/paged-stream branch from 4e9d006 to 46e175d Compare December 10, 2025 18:45
@insipx insipx force-pushed the insipx/ordered-stream branch from 950a484 to 73192df Compare December 10, 2025 18:45
@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Dec 10, 2025

Add d14n-ordered group message streams and offline causal ordering with icing in queries::d14n::XmtpMlsStreams

Introduce FlattenedStream and OrderedStream adapters and apply them to group message subscriptions to run Ordered::order_offline with a CursorStore, switch the icebox to a HashSet with recursive orphan resolution, and add a typed no-op resolver. Key changes are in streams.rs, ordered.rs, and in_memory_cursor_store.rs.

📍Where to Start

Start with the stream construction and ordering in XmtpMlsStreams at streams.rs, then review the ordering adapter in ordered.rs and the icebox behavior in in_memory_cursor_store.rs.


Macroscope summarized 76e0de7.

@insipx insipx force-pushed the insipx/ordered-stream branch from 73192df to 971b4a4 Compare December 10, 2025 19:32
@insipx insipx changed the title ordered stream type create an ordered stream Dec 10, 2025
@insipx insipx changed the title create an ordered stream create a d14n-ordered stream Dec 10, 2025
@insipx insipx force-pushed the insipx/ordered-stream branch from 971b4a4 to 5ac4ca2 Compare December 10, 2025 19:39
@insipx insipx force-pushed the insipx/paged-stream branch from 46e175d to c47bc4a Compare December 10, 2025 19:42
@insipx insipx force-pushed the insipx/ordered-stream branch from 5ac4ca2 to 5afbe75 Compare December 10, 2025 19:42
@insipx insipx force-pushed the insipx/paged-stream branch from c47bc4a to 95a95c7 Compare December 10, 2025 19:52
@insipx insipx force-pushed the insipx/ordered-stream branch 2 times, most recently from 0e4dc44 to b159bdc Compare December 10, 2025 20:12
@insipx insipx force-pushed the insipx/paged-stream branch 2 times, most recently from a8ba978 to 0cc1b60 Compare December 10, 2025 20:19
@insipx insipx force-pushed the insipx/ordered-stream branch 2 times, most recently from 254c39d to 57b66f7 Compare December 10, 2025 20:35
Base automatically changed from insipx/fake-streams to main December 11, 2025 19:56
@insipx insipx force-pushed the insipx/ordered-stream branch from d1cb961 to 4ec3e28 Compare December 11, 2025 20:42
@insipx insipx changed the base branch from main to insipx/paged-stream December 11, 2025 20:43
@insipx insipx force-pushed the insipx/ordered-stream branch from 4ec3e28 to f19d0ff Compare December 11, 2025 21:02
@insipx insipx force-pushed the insipx/paged-stream branch from 50803e3 to 8c483c4 Compare December 11, 2025 21:02
@insipx insipx force-pushed the insipx/paged-stream branch from 8c483c4 to 77f864f Compare December 15, 2025 17:18
@insipx insipx force-pushed the insipx/ordered-stream branch from f19d0ff to 189f79a Compare December 15, 2025 17:18
@insipx insipx force-pushed the insipx/ordered-stream branch from 189f79a to d0c293f Compare December 15, 2025 17:53
@insipx insipx force-pushed the insipx/paged-stream branch from 77f864f to 63b60a9 Compare December 15, 2025 17:53
@insipx insipx force-pushed the insipx/paged-stream branch from 63b60a9 to 501ea00 Compare December 15, 2025 19:08
@insipx insipx force-pushed the insipx/ordered-stream branch from d0c293f to cc932d2 Compare December 15, 2025 19:08
@insipx insipx force-pushed the insipx/paged-stream branch from 501ea00 to 786d35a Compare December 15, 2025 19:27
@insipx insipx force-pushed the insipx/ordered-stream branch from cc932d2 to 3ec02cb Compare December 15, 2025 19:27
@insipx insipx force-pushed the insipx/paged-stream branch from 786d35a to 98a9a23 Compare December 15, 2025 19:27
@insipx insipx force-pushed the insipx/ordered-stream branch from 3ec02cb to 4d7d1b4 Compare December 15, 2025 19:27
@insipx insipx force-pushed the insipx/paged-stream branch from 98a9a23 to 62346bb Compare December 15, 2025 19:27
@insipx insipx force-pushed the insipx/ordered-stream branch 2 times, most recently from 46e5a2a to 76e0de7 Compare December 15, 2025 20:15
@insipx insipx force-pushed the insipx/paged-stream branch from 62346bb to 1340914 Compare December 15, 2025 20:15
Base automatically changed from insipx/paged-stream to main December 15, 2025 20:49
@insipx insipx force-pushed the insipx/ordered-stream branch from 76e0de7 to cd80e47 Compare December 15, 2025 20:50
@insipx insipx enabled auto-merge (squash) December 15, 2025 21:00
@insipx insipx merged commit 68cd9b5 into main Dec 15, 2025
15 of 16 checks passed
@insipx insipx deleted the insipx/ordered-stream branch December 15, 2025 21:04
rygine pushed a commit that referenced this pull request Dec 28, 2025
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.

Implement stream for an Ordered stream type

3 participants