Skip to content

Improve error message when admin takes over dispute from solver#519

Merged
grunch merged 1 commit intoMostroP2P:mainfrom
Otso-Hirvikangas:feat/issue-302-admin-dispute-takeover-message
Sep 23, 2025
Merged

Improve error message when admin takes over dispute from solver#519
grunch merged 1 commit intoMostroP2P:mainfrom
Otso-Hirvikangas:feat/issue-302-admin-dispute-takeover-message

Conversation

@Otso-Hirvikangas
Copy link
Contributor

@Otso-Hirvikangas Otso-Hirvikangas commented Sep 18, 2025

Summary

Improve error messaging when admin takes over dispute from solver. Replace generic "Dispute not taken by you" with specific "DisputeTakenByAdmin" error.

Implementation

Adds is_dispute_taken_by_admin() function that checks if the current dispute solver is the admin (mostro daemon). When a solver tries to resolve a dispute that an admin has taken over, they now get a clear message explaining the situation instead of a generic error.

Tests

Includes unit test validating the new error types are accessible and distinct from existing ones.

Dependencies

  • mostro-core PR used sdk code to avoid code duplication - reduced user_rate.rs file #117 has been merged into main branch
  • Currently using git dependency: mostro-core = { git = "https://github.com/MostroP2P/mostro-core.git" }
  • Reason: Published version 0.6.50 does not include the DisputeTakenByAdmin error type
  • Next step: When mostro-core team publishes v0.6.51+ with the merged changes, this can be updated to use version dependency

Status: Ready for review

Fixes #302

Summary by CodeRabbit

  • New Features

    • Clearer feedback when cancelling or settling disputes: the app now distinguishes disputes taken over by an admin from generic "not your dispute" messages.
  • Chores

    • Updated a core dependency to a newer patch version.
  • Tests

    • Added tests to validate the new dispute-taken-by-admin messaging.

@Otso-Hirvikangas Otso-Hirvikangas force-pushed the feat/issue-302-admin-dispute-takeover-message branch from 0c390d6 to 12611dd Compare September 18, 2025 14:34
@Catrya
Copy link
Member

Catrya commented Sep 19, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 19, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 19, 2025

Walkthrough

Update mostro-core dependency version in Cargo.toml; add a new DB helper is_dispute_taken_by_admin; update admin_cancel and admin_settle handlers to return DisputeTakenByAdmin when applicable; add small tests for CantDoReason formatting.

Changes

Cohort / File(s) Summary
Dependency
Cargo.toml
Bump mostro-core from 0.6.50 to 0.6.51, keeping features = ["sqlx"].
Admin actions flow
src/app/admin_cancel.rs, src/app/admin_settle.rs
Import is_dispute_taken_by_admin. When is_assigned_solver(...).await is Ok(false), check admin takeover: return CantDoReason::DisputeTakenByAdmin if admin took the dispute, otherwise CantDoReason::IsNotYourDispute.
Database utility
src/db.rs
Add pub async fn is_dispute_taken_by_admin(pool: &SqlitePool, order_id: Uuid) -> Result<bool, MostroError>: query dispute solver_pubkey for in-progress order and compare to admin pubkey; map DB errors to MostroInternalErr.
Tests
src/app/admin_settle.rs (tests)
Add unit tests verifying CantDoReason::IsNotYourDispute and DisputeTakenByAdmin string formatting and distinctness.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Solver
  participant App as Admin Cancel/Settle Handler
  participant DB

  Solver->>App: request cancel/settle(order_id)
  App->>DB: is_assigned_solver(order_id, solver_pubkey)
  alt assigned to solver
    App-->>Solver: proceed (existing success flow)
  else not assigned
    App->>DB: is_dispute_taken_by_admin(order_id)
    alt admin took dispute
      App-->>Solver: Error: DisputeTakenByAdmin
    else admin did not take
      App-->>Solver: Error: IsNotYourDispute
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • Catrya
  • grunch

Poem

hop-hop I peered at the log,
admin’s paw left a cog;
solver sighed, carrot slipped away,
now the banter tells the day —
"Taken by admin," says the note, 🥕🐇

Pre-merge checks and finishing touches

✅ 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 concisely describes the primary change: the PR introduces logic and a new error to inform solvers when the admin takes over a dispute. It is specific and focused on the behavior change without listing files or unrelated details. This makes the intent clear to reviewers and future readers.
Linked Issues Check ✅ Passed The changes implement the linked issue's objective by adding is_dispute_taken_by_admin, updating admin_cancel and admin_settle to return DisputeTakenByAdmin when appropriate, and adding a unit test for the new error, which directly addresses informing solvers when the admin takes over (issue #302). The database helper and error-handling changes align with the coding requirements of the issue. The dependency update to mostro-core supports the new error variant used by the code.
Out of Scope Changes Check ✅ Passed All reported code changes are narrowly scoped to detecting admin takeover and returning the DisputeTakenByAdmin error, plus a related unit test and the necessary mostro-core dependency bump; there are no unrelated feature changes or refactors in the provided summaries. The Cargo.toml change appears relevant to enable the new error variant and is within scope. Therefore no out-of-scope modifications are evident from the summaries.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • 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 f4b46d7 and 577aa3b.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • Cargo.toml (1 hunks)
  • src/app/admin_cancel.rs (2 hunks)
  • src/app/admin_settle.rs (3 hunks)
  • src/db.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • Cargo.toml
  • src/app/admin_settle.rs
  • src/app/admin_cancel.rs
  • src/db.rs

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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: 0

🧹 Nitpick comments (4)
Cargo.toml (1)

67-67: Pin the git dependency to a commit (and plan revert to crates.io).

Floating at repo HEAD is non-reproducible and risky for releases. Pin to a specific commit and switch back to a version (e.g., >= 0.6.51) once published.

Apply this diff, replacing <COMMIT_SHA> with the merge commit that introduced DisputeTakenByAdmin in mostro-core:

-mostro-core = { git = "https://github.com/MostroP2P/mostro-core.git", features = ["sqlx"] }
+mostro-core = { git = "https://github.com/MostroP2P/mostro-core.git", rev = "<COMMIT_SHA>", features = ["sqlx"] }

Optionally set [package.metadata.release].publish = false until the crate version is published to avoid cargo publish failures with git deps.

src/db.rs (1)

1154-1180: Avoid magic string for status and propagate key retrieval errors (safer, more robust).

Use DisputeStatus::InProgress in the query to prevent drift, and map get_keys() errors instead of silently returning false.

Apply this diff:

 /// Check if a dispute has been taken over by admin (Mostro daemon)
 /// This helps provide better error messages when solver tries to act on admin-taken disputes
 pub async fn is_dispute_taken_by_admin(
     pool: &SqlitePool,
     order_id: Uuid,
 ) -> Result<bool, MostroError> {
-    // Get the dispute for this order
-    let dispute = sqlx::query(
-        "SELECT solver_pubkey FROM disputes WHERE order_id = ? AND status = 'in-progress'",
-    )
-    .bind(order_id)
+    // Get the dispute for this order (only active one)
+    let dispute = sqlx::query(
+        "SELECT solver_pubkey FROM disputes WHERE order_id = ? AND status = ?",
+    )
+    .bind(order_id)
+    .bind(DisputeStatus::InProgress.to_string())
     .fetch_optional(pool)
     .await
     .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
     if let Some(row) = dispute {
-        if let Some(solver_pubkey) = row.try_get::<Option<String>, _>("solver_pubkey")
-            .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))? {
-            // Check if the current solver is the admin (mostro daemon)
-            if let Ok(my_keys) = crate::util::get_keys() {
-                return Ok(solver_pubkey == my_keys.public_key().to_string());
-            }
-        }
+        let solver_pubkey: Option<String> = row
+            .try_get("solver_pubkey")
+            .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+        if let Some(solver_pubkey) = solver_pubkey {
+            // Check if the current solver is the admin (mostro daemon)
+            let my_keys = crate::util::get_keys()
+                .map_err(|e| MostroInternalErr(ServiceError::NostrError(e.to_string())))?;
+            return Ok(solver_pubkey == my_keys.public_key().to_string());
+        }
     }
 
     Ok(false)
 }
src/app/admin_cancel.rs (1)

29-34: Good: clearer error for admin takeover.

Branching to DisputeTakenByAdmin vs IsNotYourDispute improves UX as intended.

This solver-ownership check now duplicates in admin_settle.rs. Consider extracting a small helper (e.g., cant_do_for_solver(pool, sender, order_id) -> MostroError) to keep the logic in one place.

src/app/admin_settle.rs (1)

162-185: Make the test resilient: avoid asserting on Debug strings.

Comparing {:?} output is brittle. Match on variants instead.

Apply this diff:

 #[cfg(test)]
 mod tests {
     use super::*;
     use mostro_core::error::CantDoReason;
 
     /// Test that our error handling logic correctly identifies admin takeover vs regular disputes
     /// This tests the core business logic of issue #302 without complex database setup
     #[test]
     fn test_dispute_error_types() {
-        // Test that we have the correct error types available
-        // This ensures our mostro-core dependency includes the new DisputeTakenByAdmin variant
-
-        // Original error for regular dispute issues
-        let regular_error = CantDoReason::IsNotYourDispute;
-        assert_eq!(format!("{:?}", regular_error), "IsNotYourDispute");
-
-        // New error for admin takeover scenarios
-        let admin_error = CantDoReason::DisputeTakenByAdmin;
-        assert_eq!(format!("{:?}", admin_error), "DisputeTakenByAdmin");
-
-        // Verify they are different error types
-        assert_ne!(regular_error, admin_error);
+        let regular_error = CantDoReason::IsNotYourDispute;
+        let admin_error = CantDoReason::DisputeTakenByAdmin;
+        assert!(matches!(regular_error, CantDoReason::IsNotYourDispute));
+        assert!(matches!(admin_error, CantDoReason::DisputeTakenByAdmin));
+        assert_ne!(regular_error, admin_error); // sanity: distinct variants
     }
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d3d5611 and f4b46d7.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • Cargo.toml (1 hunks)
  • src/app/admin_cancel.rs (2 hunks)
  • src/app/admin_settle.rs (3 hunks)
  • src/db.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-06-25T22:48:44.741Z
Learnt from: Catrya
PR: MostroP2P/mostro#502
File: src/app/release.rs:52-55
Timestamp: 2025-06-25T22:48:44.741Z
Learning: Cross-repository dependencies in Mostro project: when PRs introduce new types like PaymentFailedInfo from mostro-core, compilation errors are expected until the dependency PR is merged and the version is updated in the consuming repository.

Applied to files:

  • Cargo.toml
🔇 Additional comments (2)
src/app/admin_settle.rs (2)

1-1: Import looks correct and scoped.

The added is_dispute_taken_by_admin import is appropriate.


32-41: Good: map solver-mismatch to DisputeTakenByAdmin when applicable.

Matches the PR objective and preserves previous behavior otherwise.

Please confirm CantDoReason::DisputeTakenByAdmin is available from the pinned mostro-core commit; otherwise, builds on fresh clones may fail until the crate release is cut.

Copy link
Member

@Catrya Catrya left a comment

Choose a reason for hiding this comment

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

tACK , thanks @Otso-Hirvikangas

@arkanoider
Copy link
Collaborator

We can merge this @Catrya @grunch ?

Copy link
Member

@grunch grunch left a comment

Choose a reason for hiding this comment

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

great job @Otso-Hirvikangas, please update mostro core version to v0.6.51

Replace generic "Dispute not taken by you" with specific "DisputeTakenByAdmin"
error when a solver tries to resolve a dispute that an admin has taken over.

- Add is_dispute_taken_by_admin() function to check if dispute solver is admin
- Update admin_cancel.rs and admin_settle.rs to use new error type
- Include unit test for error type accessibility
- Update mostro-core dependency to v0.6.51 (published version with DisputeTakenByAdmin)

Fixes MostroP2P#302
@Otso-Hirvikangas Otso-Hirvikangas force-pushed the feat/issue-302-admin-dispute-takeover-message branch from f4b46d7 to 577aa3b Compare September 23, 2025 13:43
@Otso-Hirvikangas
Copy link
Contributor Author

Otso-Hirvikangas commented Sep 23, 2025

Thanks for the feedback! mostro-core version updated.

Copy link
Member

@grunch grunch left a comment

Choose a reason for hiding this comment

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

LGTM

@grunch grunch merged commit 9ba6a05 into MostroP2P:main Sep 23, 2025
1 check passed
@Otso-Hirvikangas Otso-Hirvikangas deleted the feat/issue-302-admin-dispute-takeover-message branch September 23, 2025 16:51
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.

Inform Solver when Admin takes over dispute

4 participants