fix(wallet): consistent error handling + exit codes for balance check (closes #7889) - #8186
Conversation
/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
FlintLeng
left a comment
There was a problem hiding this comment.
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:
- Accept both
claimedanddisputedstatuses onPOST /deliver - Skip TTL expiry check for redeliveries (disputed jobs are deliberately outside the expiry sweep)
- Clear
rejection_reasonon successful redelivery (the old rejection is no longer relevant) - Log as
"redelivered"vs"delivered"for audit trail clarity
The dispute message is improved:
- Old: "Worker can re-deliver or admin can refund" (but
/deliverdidn't actually allow this) - New: Explicitly routes to
POST /agent/jobs/<id>/deliverfor re-delivery andPOST /agent/jobs/<id>/cancelfor 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.
|
This one is not blocked on review, it is blocked on CI never having run. Only the cosmetic jobs ( A rebase onto current Flagging the cause rather than leaving you guessing: this is our workflow policy, not a judgement on the change. |
Bounty issue: rustchain-bounties#16253 (7 RTC)
Wallet: RTCd1554f0f35576faf01d386a6be1c947f560dd0b7