refactor: migrate hand-written RetryableError impls to #[derive(Retryable)]#3754
refactor: migrate hand-written RetryableError impls to #[derive(Retryable)]#3754insipx wants to merge 1 commit into
Conversation
|
Claude finished @insipx's task —— View job Code Review CompleteReview Date: 2026-06-11 16:42 UTC SummaryI've reviewed the migration from hand-written AssessmentOverall Quality: ✅ Strong The migration appears well-executed with proper understanding of the macro semantics. The key patterns are correct:
Key Observations
No Issues FoundAll migrated code follows the documented macro behavior. The annotations preserve the original retry semantics as claimed. Per the PR's testing philosophy, the macro's own test suite provides the behavioral contract, which is appropriate for this type of mechanical refactor. No changes requested. The migration is correct and the -456 line reduction is a genuine improvement in maintainability. |
ApprovabilityVerdict: Needs human review 1 blocking correctness issue found. Mechanical refactor migrating hand-written RetryableError implementations to derive macros. An unresolved review comment identifies a potential compilation error (missing trait import) that should be addressed before merging. You can customize Macroscope's approvability policy. Learn more. |
8f10674 to
5642d07
Compare
1fea1d9 to
6862d93
Compare
5642d07 to
247dede
Compare
6862d93 to
4f5e8c2
Compare
Dismissing prior approval to re-evaluate 4f5e8c2
247dede to
193d75b
Compare
4f5e8c2 to
d20c21f
Compare
Dismissing prior approval to re-evaluate d20c21f
|
Both duplicate The macro now makes this class of mistake impossible: duplicate |
193d75b to
4701e13
Compare
d20c21f to
41a8704
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## insipx/retryable-derive #3754 +/- ##
===========================================================
+ Coverage 84.47% 84.83% +0.35%
===========================================================
Files 409 407 -2
Lines 60089 59573 -516
===========================================================
- Hits 50759 50537 -222
+ Misses 9330 9036 -294 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
4701e13 to
8a5996e
Compare
3348776 to
526c596
Compare
Dismissing prior approval to re-evaluate 526c596
526c596 to
89a43a6
Compare
Dismissing prior approval to re-evaluate 89a43a6
…able)]
Replaces ~47 hand-written `impl RetryableError` blocks across 8 crates (+xnet)
with the derive. Net -456 lines. Behavior preserved per-variant:
- forwarding arms -> #[retry(inherit)]
- hardcoded trues -> #[retry(true)]; all-true / inverted enums -> #[retry(default = true)]
- hardcoded falses -> unannotated (baseline)
- multi-field forwards & collection aggregation -> #[retry(when = ...)]
- ClientError::Generic -> #[retry(when = this.contains("database is locked"))]
- GroupMessageProcessingError's nested match collapsed via a new derive on
ProcessMessageWithAppDataError (gains a RetryableError<Mls> where-bound)
Equivalence was verified by an exhaustive variant-by-variant audit against the
deleted impls (~350 variants total, zero mismatches). Per-enum golden tests were
intentionally NOT kept: the macro's own test suite (18 behavior tests + 11
trybuild fixtures in #3753) is the behavioral contract, and annotations are the
source of truth thereafter — same trust model as the hand-written impls had.
Still hand-written by design: the 22 specialized RetryableError<Mls> impls for
foreign openmls/diesel types, GroupAppDataError (instantiation-specific),
ReceiveErrors/SyncSummary one-line aggregators, and test mocks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
89a43a6 to
e23fad2
Compare
Dismissing prior approval to re-evaluate e23fad2
Summary
Stacked on #3753 — merge that first. (Absorbs former #3757; one migration PR.)
Replaces ~47 hand-written
impl RetryableErrorblocks across 8 crates (+xnet) with#[derive(Retryable)]. Net −456 lines (43 files, +297/−753).How each shape migrated
#[retry(inherit)](#[from]alone does nothing)GroupError::LockUnavailable,SubscribeError::StreamStale,EnvelopeError::Decode,ApiClientError::Http/Expired, …) →#[retry(true)]ConversionError's 16 variants: zero attrs.NotFound,GrpcError,DeviceSyncError's!matches!) →#[retry(default = true)](+#[retry(false)]exceptions)ClientError::Generic(String)→#[retry(when = this.contains("database is locked"))]ApiClientError::ClientWithEndpoint,BootstrapSynthesisError::IdentityUpdateLookup,CommitLogError::FailedToSendReadd) →#[retry(when = source.is_retryable())]CommitLogError::FailedReadds) →#[retry(when = errors.iter().any(|e| e.is_retryable()))]GroupMessageProcessingError's nested match collapsed via a new derive on innerProcessMessageWithAppDataError— the one API-surface change: that generic enum gains aProcessMessageError<S>: RetryableError<Mls>where-bound (the derive's documented generics rule; sole workspace instantiation satisfies it)Testing philosophy
Per-enum golden tests are deliberately not included. The macro's own suite in #3753 (18 behavior tests + 11 trybuild fixtures) is the behavioral contract; after the one-time equivalence audit, the annotations are the source of truth — the same trust model the hand-written impls had (which were almost entirely untested). Pre-existing retry-behavior tests (e.g.
SignatureError#3394 propagation,multi_node_clientfail-fast) still pass unchanged.Equivalence audit: every migrated variant (~350 across ~47 types) was re-derived against the verbatim deleted impls by an adversarial pass — zero mismatches. (The audit tables exist as a local artifact; ask if you want them attached.)
Deliberately NOT migrated
The 22 specialized
impl RetryableError<Mls> for openmls::*/diesel orphan-rule impls (mirror-type macro support would cost more code than it removes),GroupAppDataError<SqlKeyStoreError>(instantiation-specific),ReceiveErrors/SyncSummaryone-line aggregators, test mocks. Hand-written impls are now a single explainable category: foreign-type orphan workarounds.Verification
cargo check --workspace --all-targetsclean; wasmcargo check -p xmtp_db --target wasm32-unknown-unknownclean (wasmPlatformStorageErrormigrated)-Dwarningsclean🤖 Generated with Claude Code
Note
Migrate hand-written
RetryableErrorimpls to#[derive(Retryable)]across MLS and DB cratesReplaces ~30 manual
impl RetryableErrorblocks with the#[derive(Retryable)]macro across error enums inxmtp_mls,xmtp_db,xmtp_api,xmtp_api_d14n,xmtp_proto,xmtp_id, and related crates.#[retry(inherit)],#[retry(true)],#[retry(false)],#[retry(default = true)], or predicate-based#[retry(when = ...)]attributes instead of exhaustive match arms.inherit, unconditionally retryable variants usetrue, and non-retryable defaults usefalseor no attribute.DeviceSyncErrorswitches to#[retry(default = true)]with explicit#[retry(false)]on four non-retryable variants, inverting the previous match structure.Macroscope summarized e23fad2.