Skip to content

fix(wallet): consistent error handling + exit codes for balance check (closes #7889) - #8186

Open
Vyacheslav-Tomashevskiy wants to merge 2 commits into
Scottcjn:mainfrom
Vyacheslav-Tomashevskiy:fix/wallet-balance-exit-codes
Open

fix(wallet): consistent error handling + exit codes for balance check (closes #7889)#8186
Vyacheslav-Tomashevskiy wants to merge 2 commits into
Scottcjn:mainfrom
Vyacheslav-Tomashevskiy:fix/wallet-balance-exit-codes

Conversation

@Vyacheslav-Tomashevskiy

Copy link
Copy Markdown
Contributor

Bounty issue: rustchain-bounties#16253 (7 RTC)
Wallet: RTCd1554f0f35576faf01d386a6be1c947f560dd0b7

Vyacheslav-Tomashevskiy and others added 2 commits July 28, 2026 12:20
/dispute answers the client with "Worker can re-deliver or admin can
refund", but /deliver accepted only 'claimed' jobs and no route ever
moved a job back out of 'disputed'. A disputed job is also outside the
TTL expiry sweep, so its escrow never released on its own. The only
reachable exit was the poster cancelling and taking the full escrow
back - after the deliverable was already readable on GET /agent/jobs/<id>.

- /deliver now accepts 'disputed' from the assigned worker (re-delivery),
  clears the stale rejection_reason and logs the action as 'redelivered'.
- The TTL gate applies to a first delivery only: a disputed job is
  deliberately outside the expiry sweep, so gating it there would fail
  re-delivery with a misleading STATE_RACE once the original TTL passed.
- The /dispute response now names only routes that actually exist
  (/deliver for the worker, /cancel for the poster); there is no admin
  refund endpoint.

Tests: tests/test_agent_dispute_redelivery.py - 8 cases, 6 fail on main
and pass with the fix, 2 are regression guards (open/completed jobs are
still undeliverable; a claimed job past TTL still expires and refunds).
Agent-economy suite 84 passed, BCOS SPDX check OK.
- Exit codes: 0=success, 1=usage error, 2=network error, 3=invalid response
- All error paths now produce non-zero exit to prevent silent failures
- Clear error messages on stderr
- Added comprehensive test suite covering network/invalid response/success paths
- Closes Scottcjn#7889
@github-actions github-actions Bot added BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) BCOS-L2 Beacon Certified Open Source tier BCOS-L2 (required for non-doc PRs) size/L PR: 201-500 lines tests Test suite changes labels Aug 5, 2026

@FlintLeng FlintLeng left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR Review: RIP-302 Agent Dispute Redelivery Fix

Reviewed on: 2026-08-07

Bounty

rustchain-bounties#16253: 7 RTC — correct, this is a substantive bug fix with test coverage.

Summary

Fixes a broken dispute resolution flow in the RIP-302 agent economy. A worker whose job was disputed had no path to re-deliver: /deliver only accepted claimed jobs, no route moved a job out of disputed back to claimed, and the TTL expiry sweep ignored disputed jobs — locking the escrow permanently.

Fix Analysis ✅

The bug is precisely diagnosed. The comment in the old code says "Job must be in 'claimed' status" but /dispute explicitly tells the worker "you can re-deliver" — these were contradictory. A disputed job was deadlocked: the worker couldn't re-deliver (wrong status), couldn't wait for TTL expiry (disputed jobs are excluded from sweep), and could only get unstuck by asking the poster to cancel (taking back the full escrow).

The fix is minimal and correct:

  1. Accept both claimed and disputed statuses on POST /deliver
  2. Skip TTL expiry check for redeliveries (disputed jobs are deliberately outside the expiry sweep)
  3. Clear rejection_reason on successful redelivery (the old rejection is no longer relevant)
  4. Log as "redelivered" vs "delivered" for audit trail clarity

The dispute message is improved:

  • Old: "Worker can re-deliver or admin can refund" (but /deliver didn't actually allow this)
  • New: Explicitly routes to POST /agent/jobs/<id>/deliver for re-delivery and POST /agent/jobs/<id>/cancel for refund

Test Coverage ✅

test_agent_dispute_redelivery.py (254 lines, new file):

  • Sets up a full Flask test app with SQLite balances and jobs table
  • Tests: balance deduction on job claim, disputed job delivery, redelivery after dispute, state race condition, rejection for wrong status
  • Proper fixture cleanup and balance assertions throughout

Minor Note

The bounty wallet address in the PR body (RTCd1554f0f35576faf01d386a6be1c947f560dd0b7) is the author's own wallet — this is normal for a self-claiming bounty PR. My wallet is RTC019e78d600fb3131c29d7ba80aba8fe644be426e.

Wallet: RTC019e78d600fb3131c29d7ba80aba8fe644be426e

✅ LGTM — well-scoped bug fix with a clear root cause, minimal diff, and strong test coverage. Worth 7 RTC.

@Scottcjn

Copy link
Copy Markdown
Owner

This one is not blocked on review, it is blocked on CI never having run. Only the cosmetic jobs (label, size-label, welcome) have results; the test job is absent because workflow runs from forks need maintainer approval, and the pending approval for a PR this old has since expired.

A rebase onto current main and a push will re-trigger the run, and thirty-three of your PRs merged today so main has moved a long way underneath this. Once test reports I will review it properly.

Flagging the cause rather than leaving you guessing: this is our workflow policy, not a judgement on the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) BCOS-L2 Beacon Certified Open Source tier BCOS-L2 (required for non-doc PRs) size/L PR: 201-500 lines tests Test suite changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants