Skip to content

fix(reputation): export failures no longer read as an invalid paste - #887

Open
grunch wants to merge 2 commits into
mainfrom
fix/reputation-export-errors
Open

grunch wants to merge 2 commits into
mainfrom
fix/reputation-export-errors

Conversation

@grunch

@grunch grunch commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Linked issue

Closes #882. Part of #674.

Type

fix

What changes and why

On the Reputation screen, an export that failed for a reason without a message of its own read "This is not a valid reputation. Request it again from its source." The user is on the source and pasted nothing, so the message pointed them nowhere. That text is the default fallback of localizedReputationError, which fits the import screen, and the export handler passed no fallback of its own.

The export handler now falls back to "This Mostro could not export your reputation. Try again later." An answer signed by another key than the reputation_issuer the app read for the node (for example after the operator rotated it while the cached info event is stale) gets a marker of its own in Rust, ReputationIssuerKeyMismatch, and its own text: "This Mostro signed the answer with a key other than the one it announced. Switch to another Mostro and back to refresh its info, then try again." That is the remedy the app offers: the capability fetch runs when the relay pool comes online and after a node switch.

One correction to the issue: StorageUnavailable already had a text of its own through localizedDaemonError ("…local database is unavailable. Restart the app…"), so it never showed the invalid-reputation text. The failures that did are InvalidPayload, a destination mismatch, and node refusals with no marker in the map (invalid_action, invalid_payload).

Affected flow

Settings → Reputation (/reputation), the Export action, on failure only. Rust: check_exported in rust/src/api/reputation_transfer.rs now distinguishes the signing key from the destination (no bridge signature changes, no regenerated code). Dart: localizedReputationError in lib/features/reputation/reputation_errors.dart maps the new marker; _export in lib/features/reputation/screens/reputation_screen.dart passes the fallback. No order or dispute status is touched.

Blast radius

  • Error markers: InvalidReputationAttestation from check_exported now means only "names another identity"; the wrong-key case moved to ReputationIssuerKeyMismatch. The import path is untouched: its checks (check_importable, the parse) keep their markers, and the import screen keeps its default fallback.
  • Localization: new keys reputationExportFailed, reputationExportUnexpectedIssuer in all seven ARBs; app_localizations*.dart regenerated with flutter gen-l10n, untranslated report empty.
  • Spec: the export_reputation errors list in specs/004-mostro-p2p-client/contracts/reputation_transfer.md names the new marker and what the screen shows.
  • Bridge, persisted data, other platforms, wire, automation identifiers: untouched.

Platforms tested

None by hand. See Manual testing.

Manual testing

Not run: this branch was verified with cargo test, flutter analyze and flutter test only; I did not run the app against a node. The steps a person should run:

Setup

App built from this branch with flutter run -d linux (debug), identity in Reputation Mode, active node advertising reputation_issuer.

Steps

  1. On a node whose operator stopped exporting (or removed reputation_issuer from its info event) after the app read it, Settings → Reputation → Export → confirm.
    Expected: "This Mostro could not export your reputation. Try again later." On main: "This is not a valid reputation. Request it again from its source." (fails on main).
  2. On a node whose operator rotated REPUTATION_ISSUER_SK after the app read its info event, Export → confirm.
    Expected: "This Mostro signed the answer with a key other than the one it announced. Switch to another Mostro and back to refresh its info, then try again." After switching nodes and back, Export succeeds.
  3. Regression: on a node that refuses with NotEligibleForReputationExport, Export → confirm.
    Expected: the "at least 10 completed trades" message, as before.
  4. Regression: Import reputation → paste text that is not an attestation → Check.
    Expected: "This is not a valid reputation. Request it again from its source.", as before.

Not covered

Nothing was run by hand. iOS, Android, web: not run.

Screenshots

No visible change apart from the error text on failure; pending an app run.

Automated tests

First commit (test:), failing on main:

  • Rust an_export_answer_must_come_from_the_advertised_issuer_for_the_asked_identity: the wrong-key case now expects ReputationIssuerKeyMismatch (fails on main: InvalidReputationAttestation).
  • test/features/reputation/reputation_screen_test.dart: an export that fails for a reason without a message of its own says this Mostro could not export (fails on main with the invalid-reputation text) and an answer signed by another key than the one the node announced says to refresh its info.
  • test/features/reputation/reputation_errors_test.dart (new): a known marker wins over the fallback; a failure without a marker reads as the fallback; without a fallback it reads as an invalid attestation (the import screen's default, unchanged); the new marker has its own text (fails on main).
07:50 +3092 ~4: All tests passed!
cargo test --lib reputation: test result: ok. 54 passed; 0 failed

Checklist

  • cd rust && cargo fmt --check && cargo clippy -- -D warnings && cargo test pass locally — cargo test passes; with my local toolchain cargo fmt --check and cargo clippy --all-targets -- -D warnings report the same pre-existing findings on main (505 fmt diffs, 27 clippy lints), none in the file this PR touches; rustfmt --check on it is clean
  • dart format --set-exit-if-changed ., flutter analyze and flutter test pass locally (flutter test summary line pasted under Automated tests)
  • Changed rust/src/api/ or an .arb: regenerated code committed in the same commit (CONTRIBUTING.md § Generated code) — no bridge signature changed; l10n regenerated
  • New or changed user-facing text: every locale updated, no hardcoded strings
  • Changed an automation identifier: coordinated in the linked issue (docs/automation-contract.md) — none
  • Protocol or transport change: impact on the daemon and other clients stated (CONTRIBUTING.md § Protocol / Transport Changes) — none
  • Behaviour or contract change: matching spec under specs/ or .specify/ updated
  • Commits are signed
  • I ran the Manual testing steps myself and can explain every line of this diff — the steps were not run; the diff is explained above

AI assistance

Written with Claude Code (Claude Fable 5.1) from the issue; the maintainer reviews the diff and runs the manual steps.

🤖 Generated with Claude Code

https://claude.ai/code/session_0126k49pgKzD8NA7SzMHepcJ

Summary by CodeRabbit

  • Bug Fixes
    • Reputation export now distinguishes unexpected signing keys from other export failures, with clearer, localized messages and guidance to refresh node information before retrying.
    • Other export errors now display a general failure message rather than an unrelated invalid-reputation message.
  • Documentation
    • Clarified how reputation export errors are reported.

grunch and others added 2 commits October 23, 2026 16:24
Regression tests for #882, failing on main: an export that fails for a
reason without a message of its own (InvalidPayload here) reads as a
pasted invalid attestation, and an answer signed by another key than
the node announced has no message of its own, in Rust or in Dart.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126k49pgKzD8NA7SzMHepcJ
On the Reputation screen, an export that failed for a reason without a
message of its own said "This is not a valid reputation. Request it
again from its source." The user is on the source and pasted nothing.

The export handler now falls back to "This Mostro could not export your
reputation. Try again later." An answer signed by another key than the
reputation_issuer the app read for the node gets its own marker,
ReputationIssuerKeyMismatch, and a text that says to refresh the node's
info by switching Mostro and back. StorageUnavailable already had a text
of its own; InvalidPayload, a destination mismatch and unmapped node
refusals were the cases that showed the wrong text.

Closes #882

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126k49pgKzD8NA7SzMHepcJ
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T19:37:11.210730Z 233fc7d PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between 93ba348 and 233fc7d.

📒 Files selected for processing: 21
  • lib/features/reputation/reputation_errors.dart
  • lib/features/reputation/screens/reputation_screen.dart
  • lib/l10n/app_de.arb
  • lib/l10n/app_en.arb
  • lib/l10n/app_es.arb
  • lib/l10n/app_fr.arb
  • lib/l10n/app_it.arb
  • lib/l10n/app_localizations.dart
  • lib/l10n/app_localizations_de.dart
  • lib/l10n/app_localizations_en.dart
  • lib/l10n/app_localizations_es.dart
  • lib/l10n/app_localizations_fr.dart
  • lib/l10n/app_localizations_it.dart
  • lib/l10n/app_localizations_nl.dart
  • lib/l10n/app_localizations_pt.dart
  • lib/l10n/app_nl.arb
  • lib/l10n/app_pt.arb
  • rust/src/api/reputation_transfer.rs
  • specs/004-mostro-p2p-client/contracts/reputation_transfer.md
  • test/features/reputation/reputation_errors_test.dart
  • test/features/reputation/reputation_screen_test.dart

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

Backend export validation now identifies issuer-key mismatches separately from destination mismatches. The reputation screen uses dedicated text for issuer-key errors and a generic export-failure fallback for other errors. Localization strings, tests, and contract documentation were added or updated.

Changes

Reputation export errors

Layer / File(s) Summary
Classify issuer-key mismatches
rust/src/api/reputation_transfer.rs, specs/004-mostro-p2p-client/contracts/reputation_transfer.md
check_exported reports ReputationIssuerKeyMismatch for an issuer-key mismatch and retains InvalidReputationAttestation for a destination mismatch. The contract documents the error and its handling.
Map export errors to localized messages
lib/features/reputation/*, lib/l10n/*, test/features/reputation/*
The export screen supplies a generic fallback and maps issuer-key mismatches to dedicated text. English, German, Spanish, French, Italian, Dutch, and Portuguese messages and tests cover the updated behavior.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: forte11cuba

Merge Risk: ⚪ Minimal · up to 233fc

No actionable merge-blocking risk was established; the export-specific error handling is ready to merge.

Pre-merge checks: Passed 5
Check name Status Explanation
Title check Passed The title clearly identifies the main change: export failures no longer display the invalid-reputation message.
Description check Passed The description is detailed and covers the change, affected flow, blast radius, testing, localization, specification updates, and known limitations. It also clearly states that manual testing was not …
Linked Issues check Passed Issue #882 requires an export-specific fallback and a distinct error for a response signed by an unexpected issuer key. _export now passes l10n.reputationExportFailed as the fallback. `check_expor…
Out of Scope Changes check Passed The changes stay within issue #882. Rust marker handling, export-screen fallback handling, localization, generated localization code, tests, and the reputation transfer specification directly support …
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 1 files. (20 skipped: 2…
Full details: Description check

Explanation

The description is detailed and covers the change, affected flow, blast radius, testing, localization, specification updates, and known limitations. It also clearly states that manual testing was not run and that screenshots are pending for the changed error text.

Full details: Linked Issues check

Explanation

Issue #882 requires an export-specific fallback and a distinct error for a response signed by an unexpected issuer key. _export now passes l10n.reputationExportFailed as the fallback. check_exported now emits ReputationIssuerKeyMismatch for an issuer-key mismatch and keeps destination mismatches as InvalidReputationAttestation. localizedReputationError maps the new marker. The PR also adds localization, spec, Rust, and widget tests. The parent issue #674 supplies context only.

Full details: Out of Scope Changes check

Explanation

The changes stay within issue #882. Rust marker handling, export-screen fallback handling, localization, generated localization code, tests, and the reputation transfer specification directly support the requested behavior. The described import path, bridge, persisted data, other platforms, wire behavior, and order or dispute status remain unchanged.

Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 1 files. (20 skipped: 20 unsupported.)

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

A rabbit checks the export trail,
A key mismatch gets a message, not a tale.
If other errors block the way,
A clear retry note has its say.
Then hops away with carrots in its pail.

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
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.

fix(reputation): export failures say "This is not a valid reputation"

1 participant