Skip to content

Check initiator to restored dispute data#497

Open
BraCR10 wants to merge 2 commits intomainfrom
fix/restoreDisputeCreator
Open

Check initiator to restored dispute data#497
BraCR10 wants to merge 2 commits intomainfrom
fix/restoreDisputeCreator

Conversation

@BraCR10
Copy link
Member

@BraCR10 BraCR10 commented Feb 24, 2026

Summary

Fixed dispute initiator detection during order restoration using the initiator field from Mostro protocol.

Changes:

  • Added initiator: String? field to RestoredDispute model
  • Simplified dispute detection logic in RestoreManager to directly compare initiator ("buyer"/"seller") with user's role
  • Removed complex _determineIfUserInitiatedDispute() method

Test plan

  1. Create two disputes: one as buyer, one as seller
  2. Clear app data and restore from mnemonic
  3. Expected: Disputes show correct initiator in "My Trades"
    • Your dispute: "You opened this dispute"
    • Peer dispute: "A dispute was opened against you"
  4. Verify logs show successful initiator field parsing

Closes #401

Summary by CodeRabbit

  • Bug Fixes
    • More reliable detection of which party initiated a dispute during restoration.
    • Restored records can now include an optional initiator value (normalized to "buyer" or "seller").
    • Restore flow simplified to derive initiation from available initiator and current role, defaulting to peer-initiated when unknown.

Adds the 'initiator' field to the `RestoredDispute` model
to indicate which party initiated the dispute, simplifying
the dispute initiation detection logic and removing the
need for trade index comparison.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7fd35f2 and 2b70163.

📒 Files selected for processing (1)
  • lib/data/models/restore_response.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/data/models/restore_response.dart

Walkthrough

Added an optional initiator field to RestoredDispute and simplified the restore manager by removing a helper and inlining dispute-initiator determination using the new field and session role.

Changes

Cohort / File(s) Summary
Data Model Enhancement
lib/data/models/restore_response.dart
Added optional initiator (String?) to RestoredDispute; updated constructor, fromJson (with _normalizeInitiator), and toJson to conditionally include the field.
Restore Logic Simplification
lib/features/restore/restore_manager.dart
Removed _determineIfUserInitiatedDispute; inlined logic to decide userInitiated from restoredDispute.initiator and current session role, and map to Action.disputeInitiatedByYou / Action.disputeInitiatedByPeer.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

  • mostro#598: Same initiator field added to restore dispute payloads and consumed during restore — directly related.
  • mostro-core#129: Adds initiator to restored-dispute structures and adjusts restore-path mapping — related to this model + logic change.
  • #401: Determine which user opened a dispute when import user — this PR implements the initiator support referenced by the issue.

Poem

🐰 Soft paws on keys at break of dawn,
I found who started the quarrel drawn.
With initiator clear and neat,
Restore flows now skip a beat.
Hooray — disputes sorted, hoppity on!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding an initiator field to restored dispute data to determine which party opened a dispute.
Linked Issues check ✅ Passed The pull request successfully implements all coding requirements from issue #401: adds initiator field to RestoredDispute model, normalizes initiator values (buyer/seller), and simplifies dispute detection logic using the new field.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #401 requirements. The modifications to RestoredDispute model and RestoreManager simplify dispute initiator detection without introducing unrelated functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/restoreDisputeCreator

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.

🧹 Nitpick comments (2)
lib/data/models/restore_response.dart (1)

63-94: Normalize/validate initiator during deserialization.

Using raw strings makes downstream checks fragile if the protocol ever changes casing or sends unexpected values; consider lowercasing and allow‑listing buyer/seller (or mapping to an enum) so unknown values become null consistently.

♻️ Suggested adjustment
   factory RestoredDispute.fromJson(Map<String, dynamic> json) {
+    final rawInitiator = (json['initiator'] as String?)?.toLowerCase();
+    final initiator = (rawInitiator == 'buyer' || rawInitiator == 'seller')
+        ? rawInitiator
+        : null;
     return RestoredDispute(
       disputeId: json['dispute_id'] as String,
       orderId: json['order_id'] as String,
       tradeIndex: json['trade_index'] as int,
       status: json['status'] as String,
-      initiator: json['initiator'] as String?,
+      initiator: initiator,
     );
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/data/models/restore_response.dart` around lines 63 - 94,
RestoredDispute.fromJson currently assigns initiator directly from JSON which
may vary in casing or unexpected values; update RestoredDispute.fromJson to
normalize and allow‑list the initiator field (e.g., lowercase the input and
accept only "buyer" or "seller", otherwise set initiator to null or map into an
enum) so downstream checks are stable; modify the factory
RestoredDispute.fromJson to perform this validation/normalization before
assigning the initiator property and ensure any mapping uses the
RestoredDispute.initiator field (or a new enum) consistently.
lib/features/restore/restore_manager.dart (1)

589-596: Normalize initiator before role comparison.

The comparison is currently case-sensitive; normalizing avoids mislabeling disputes if upstream sends “Buyer/Seller” or other casing variants.

♻️ Suggested adjustment
-            final userInitiated = restoredDispute.initiator != null && session?.role != null
-                ? (session!.role == Role.buyer && restoredDispute.initiator == 'buyer') ||
-                  (session.role == Role.seller && restoredDispute.initiator == 'seller')
-                : false;
+            final initiator = restoredDispute.initiator?.toLowerCase();
+            final userInitiated = initiator != null && session?.role != null
+                ? (session!.role == Role.buyer && initiator == 'buyer') ||
+                  (session.role == Role.seller && initiator == 'seller')
+                : false;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/features/restore/restore_manager.dart` around lines 589 - 596, The
initiator string comparison is case-sensitive; normalize
restoredDispute.initiator before comparing to session.role to avoid mismatches.
Trim and convert restoredDispute.initiator to a consistent case (e.g.,
lowerCase) and then compare that normalized value to 'buyer'/'seller' (or Role
enum names normalized) when computing userInitiated within the block that
references restoredDispute.initiator, session.role, Role.buyer, Role.seller and
setting action to Action.disputeInitiatedByYou/Action.disputeInitiatedByPeer.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@lib/data/models/restore_response.dart`:
- Around line 63-94: RestoredDispute.fromJson currently assigns initiator
directly from JSON which may vary in casing or unexpected values; update
RestoredDispute.fromJson to normalize and allow‑list the initiator field (e.g.,
lowercase the input and accept only "buyer" or "seller", otherwise set initiator
to null or map into an enum) so downstream checks are stable; modify the factory
RestoredDispute.fromJson to perform this validation/normalization before
assigning the initiator property and ensure any mapping uses the
RestoredDispute.initiator field (or a new enum) consistently.

In `@lib/features/restore/restore_manager.dart`:
- Around line 589-596: The initiator string comparison is case-sensitive;
normalize restoredDispute.initiator before comparing to session.role to avoid
mismatches. Trim and convert restoredDispute.initiator to a consistent case
(e.g., lowerCase) and then compare that normalized value to 'buyer'/'seller' (or
Role enum names normalized) when computing userInitiated within the block that
references restoredDispute.initiator, session.role, Role.buyer, Role.seller and
setting action to Action.disputeInitiatedByYou/Action.disputeInitiatedByPeer.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 149010c and 7fd35f2.

📒 Files selected for processing (2)
  • lib/data/models/restore_response.dart
  • lib/features/restore/restore_manager.dart

Normalizes the `initiator` field in the `RestoredDispute` model
to ensure consistency. It trims whitespace and converts the value
to lowercase before validation.  If the normalized value is
'buyer' or 'seller', it's returned; otherwise, it returns null.
This prevents issues caused by inconsistent initiator naming when
restoring disputes.
@grunch grunch requested a review from Catrya February 24, 2026 12:09
Copy link
Contributor

@mostronatorcoder mostronatorcoder bot left a comment

Choose a reason for hiding this comment

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

Good simplification overall — using the initiator field from the protocol is much cleaner than the old trade-index heuristic. However, there are a few issues that need attention before merging:

Issues

1. String comparison for role matching is fragile

The logic at line ~591 compares session.role == Role.buyer with restoredDispute.initiator == 'buyer'. This relies on the string "buyer"/"seller" matching the enum semantics forever. If the Role enum or the protocol ever changes the string representation, this silently breaks.

Suggestion: Add a helper method or extension on Role to make this explicit and type-safe:

bool get isBuyer => this == Role.buyer;
String get initiatorValue => this == Role.buyer ? 'buyer' : 'seller';

Then the comparison becomes:

final userInitiated = restoredDispute.initiator != null && session?.role != null
    ? session!.role.initiatorValue == restoredDispute.initiator
    : false;

This eliminates the duplicated buyer/seller string checks and makes it a single comparison.

2. Missing test coverage

The old method had complex logic that was presumably untested (since it was wrong). The new logic is simpler but still has branching paths:

  • initiator is null → defaults to peer
  • session is null → defaults to peer
  • initiator is "buyer" and role is buyer → user initiated
  • initiator is "seller" and role is buyer → peer initiated
  • Edge: initiator is some unexpected string → _normalizeInitiator returns null → peer

Per the repo's AGENTS.md: "Add targeted scenarios when expanding complex logic or async workflows." At minimum, unit tests for _normalizeInitiator and the initiator-matching logic should be included.

3. _normalizeInitiator is private static but could be useful elsewhere

If dispute initiator normalization is needed in other contexts (e.g., future dispute list views), this will need to be extracted. Consider making it a package-private utility or a method on RestoredDispute that's accessible.

4. tradeIndex is now unused for dispute detection

The tradeIndex field on RestoredDispute was previously the core of dispute detection. Now it's only used for... what? If it's still needed for session matching elsewhere, fine. If not, document why it's kept (or remove it if truly unused).

What looks good

  • _normalizeInitiator with whitelist validation is solid defensive coding
  • ✅ CI passes, no conflicts with main
  • ✅ The simplification removes ~60 lines of complex, error-prone logic
  • ✅ Conditional serialization in toJson (if (initiator != null)) is clean

Please address #1 and #2 at minimum.

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.

Determine which user opened a dispute when import user

1 participant