-
Notifications
You must be signed in to change notification settings - Fork 74
add icebox to OrderedEnvelopeCollection implementation
#2882
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
This PR is part of a stack of 12 bookmarks:
Created with jj-stack |
|
Claude finished @insipx's task —— View job PR Review - December 15, 2025, 7:10 PM UTCThis PR successfully integrates icebox functionality into the ordering flow. The core implementation is solid with good property-based testing. Here are the key findings: Critical Issues1. Decode Error Retryability (xmtp_api_d14n/src/protocol/traits.rs:88)
Correctness Concerns2. Potential Infinite Loop in Recovery (xmtp_api_d14n/src/protocol/order.rs:136)
3. Unresolved Dependencies Silently Dropped (xmtp_api_d14n/src/protocol/order.rs:128)
Design Observations4. Test Coverage for Icebox Recovery (xmtp_api_d14n/src/protocol/order.rs:67-95)
5. Performance: Multiple HashSet Constructions (xmtp_api_d14n/src/protocol/order.rs:68-83)
Security & SafetyNo security concerns identified. The changes maintain proper error handling and don't introduce unsafe operations. SummaryThe core icebox integration is well-designed with solid property-based testing. Main concerns are:
The codecov report shows 83.7% patch coverage with 22 missing lines. Missing coverage appears concentrated in error paths and test utilities, which is acceptable. |
83b5cb3 to
12d47bd
Compare
a81a59b to
da907f5
Compare
12d47bd to
6e03d9f
Compare
da907f5 to
c5e17ad
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2882 +/- ##
==========================================
+ Coverage 73.49% 73.61% +0.11%
==========================================
Files 405 405
Lines 51656 51710 +54
==========================================
+ Hits 37965 38064 +99
+ Misses 13691 13646 -45 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
c5e17ad to
4f2808e
Compare
6e03d9f to
d7c373b
Compare
4f2808e to
80f2a62
Compare
d7c373b to
798f6ab
Compare
80f2a62 to
9d5c60c
Compare
798f6ab to
c7cbc5c
Compare
c7cbc5c to
f5c5824
Compare
fe451e6 to
c8856e5
Compare
c49f3ba to
e3540d3
Compare
c8856e5 to
37ca7b6
Compare
OrderedEnvelopeCollection implementation
37ca7b6 to
b4407a8
Compare
e3540d3 to
7a08a24
Compare
7a08a24 to
e626807
Compare
3b21dc8 to
9a5370b
Compare
e626807 to
35ec6e7
Compare
9a5370b to
debc116
Compare
debc116 to
5ab6d8e
Compare
5ab6d8e to
7840c4a
Compare
7840c4a to
38c66a7
Compare
<!-- Macroscope's pull request summary starts here --> <!-- Macroscope will only edit the content between these invisible markers, and the markers themselves will not be visible in the GitHub rendered markdown. --> <!-- If you delete either of the start / end markers from your PR's description, Macroscope will post its summary as a comment. --> ### Add icebox support to `protocol.order.OrderedEnvelopeCollection::order` by integrating a `CursorStore` into `Ordered` and the ordered query path Introduce a store-backed ordering flow that computes `RequiredDependency`, ices unresolved envelopes, and periodically recovers orphaned children, updating resolver signatures to use `RequiredDependency` and removing `Envelope::consume`. Key changes land in [order.rs](https://github.com/xmtp/libxmtp/pull/2882/files#diff-78b9f275c691ca4b70a53c2a710b84b741cf86e28ac909dc8b250cbe9b61ed1e) with corresponding combinator and resolver updates. #### 📍Where to Start Start with `Ordered<T, R, S>::order` in [order.rs](https://github.com/xmtp/libxmtp/pull/2882/files#diff-78b9f275c691ca4b70a53c2a710b84b741cf86e28ac909dc8b250cbe9b61ed1e), then review the `ResolveDependencies` signature change and handling of `RequiredDependency` in [network_backoff.rs](https://github.com/xmtp/libxmtp/pull/2882/files#diff-de7799794fbc3300554d0474e251ec4117a5b0773a085ba0f94dd6f863c2f51e). ---- <!-- Macroscope's review summary starts here --> <details> <summary>📊 <a href="https://app.macroscope.com">Macroscope</a> summarized 7840c4a. 12 files reviewed, 5 issues evaluated, 5 issues filtered, 0 comments posted</summary> ### 🗂️ Filtered Issues <details> <summary>xmtp_api_d14n/src/protocol/order.rs — 0 comments posted, 3 evaluated, 3 filtered</summary> - [line 87](https://github.com/xmtp/libxmtp/blob/7840c4a18d70ca3574b8d1e9cdf7449354df8fa5/xmtp_api_d14n/src/protocol/order.rs#L87): In `recover_lost_children`, orphaned envelopes retrieved from the store are decoded using `T::decode` and any `prost::DecodeError` will propagate as `EnvelopeError::Decode`. However, in the `RetryableError` impl at line 87 of `traits.rs`, `Self::Decode(_) => true` marks decode errors as retryable. Decode errors typically indicate malformed/corrupted data that won't be fixed by retrying, so this could cause unnecessary retry loops. <b>[ Already posted ]</b> - [line 125](https://github.com/xmtp/libxmtp/blob/7840c4a18d70ca3574b8d1e9cdf7449354df8fa5/xmtp_api_d14n/src/protocol/order.rs#L125): The `unresolved` field from `Resolved` is ignored with the `..` pattern on line 125. If the resolver returns partial results where some dependencies are resolved and some are `unresolved`, the unresolved dependencies are no longer tracked or handled. The old code explicitly handled unresolved envelopes by removing them from the missing list. Now, if resolution returns some resolved items but also reports some as unresolved, those unresolved envelopes will just be re-appended and potentially loop until they eventually get iced when `resolved.is_empty()`, which may never happen if other unrelated envelopes keep getting resolved. <b>[ Low confidence ]</b> - [line 173](https://github.com/xmtp/libxmtp/blob/7840c4a18d70ca3574b8d1e9cdf7449354df8fa5/xmtp_api_d14n/src/protocol/order.rs#L173): The resolver now only matches envelopes by `cursor`, ignoring the `topic` that was previously checked. If cursors are not globally unique and can repeat across different topics, this could return incorrect envelopes that happen to share the same cursor but belong to a different topic. The old code verified both `topic` AND `cursor` matched via `MissingEnvelope::new(topic, cursor)`, but the new code discards topic information entirely. <b>[ Previously rejected ]</b> </details> <details> <summary>xmtp_api_d14n/src/protocol/resolve/network_backoff.rs — 0 comments posted, 1 evaluated, 1 filtered</summary> - [line 53](https://github.com/xmtp/libxmtp/blob/7840c4a18d70ca3574b8d1e9cdf7449354df8fa5/xmtp_api_d14n/src/protocol/resolve/network_backoff.rs#L53): The `resolve` function sleeps before making the first network query. On the first iteration with `attempts = 0`, `self.backoff.backoff(0, time_spent)` returns `Some(duration)` (base duration + jitter), causing an unnecessary delay before any query attempt. The first resolution attempt should be made immediately without sleeping. <b>[ Out of scope ]</b> </details> <details> <summary>xmtp_api_d14n/src/protocol/traits.rs — 0 comments posted, 1 evaluated, 1 filtered</summary> - [line 88](https://github.com/xmtp/libxmtp/blob/7840c4a18d70ca3574b8d1e9cdf7449354df8fa5/xmtp_api_d14n/src/protocol/traits.rs#L88): In `is_retryable()` for `EnvelopeError`, `Self::Decode(_) => true` marks `prost::DecodeError` as retryable. However, decode errors indicate malformed protobuf bytes, and retrying a decode operation on the same malformed bytes will produce the same error. This is inconsistent with the rationale documented in `ConversionError`'s `is_retryable()` implementation which explicitly states that conversions are not retryable because "the bytes are static". This could cause infinite retry loops or wasted retry attempts on permanently failing operations. <b>[ Already posted ]</b> </details> </details><!-- Macroscope's review summary ends here --> <!-- macroscope-ui-refresh --> <!-- Macroscope's pull request summary ends here -->
Add icebox support by requiring a
CursorStoreinprotocol.order.Orderedand icing unresolved orphans duringOrderedEnvelopeCollection::orderIntroduce a store-backed ordering flow that recovers children, sorts by timestamp/causal order, requests dependencies as
RequiredDependency, and ices unresolved orphans in the store; update resolver and traits to acceptRequiredDependencyand propagate store/decode errors. Core changes center onprotocol.order.Orderedand dependent combinators/resolvers, withEnvelopedroppingconsumeand tests updated accordingly.📍Where to Start
Start with the
OrderedEnvelopeCollection for Ordered::orderimplementation in order.rs, then reviewrequired_dependencies,recover_lost_children, and the resolver changes in network_backoff.rs.📊 Macroscope summarized 38c66a7. 12 files reviewed, 3 issues evaluated, 3 issues filtered, 0 comments posted
🗂️ Filtered Issues
xmtp_api_d14n/src/protocol/order.rs — 0 comments posted, 1 evaluated, 1 filtered
topicANDcursorusingMissingEnvelope::new(topic, cursor), but the new code only matches bycursoralone. This could cause the resolver to return envelopes with matching cursors but incorrect topics, potentially masking bugs where topic matching is important. IfRequiredDependencycontains topic information that should be used for matching, it's being ignored. [ Previously rejected ]xmtp_api_d14n/src/protocol/resolve/network_backoff.rs — 0 comments posted, 1 evaluated, 1 filtered
resolvefunction sleeps before making the first network query. On the first iteration withattempts = 0,self.backoff.backoff(0, time_spent)returnsSome(duration)(base duration + jitter), causing an unnecessary delay before any query attempt. The first resolution attempt should be made immediately without sleeping. [ Out of scope ]xmtp_api_d14n/src/protocol/traits.rs — 0 comments posted, 1 evaluated, 1 filtered
is_retryable()forEnvelopeError,Self::Decode(_) => truemarksprost::DecodeErroras retryable. However, decode errors indicate malformed protobuf bytes, and retrying a decode operation on the same malformed bytes will produce the same error. This is inconsistent with the rationale documented inConversionError'sis_retryable()implementation which explicitly states that conversions are not retryable because "the bytes are static". This could cause infinite retry loops or wasted retry attempts on permanently failing operations. [ Already posted ]