Skip to content

fix(bounties): make expireOverdue atomic and state-machine safe - #717

Open
Youngthreader wants to merge 1 commit into
MergeFi:mainfrom
Youngthreader:fix/issue-460-bountiesservice-expireoverdue-overwrites
Open

Youngthreader wants to merge 1 commit into
MergeFi:mainfrom
Youngthreader:fix/issue-460-bountiesservice-expireoverdue-overwrites

Conversation

@Youngthreader

Copy link
Copy Markdown

Overview

This PR fixes BountiesService.expireOverdue() so that it no longer overwrites bounties that were advanced concurrently by webhooks. The expiry sweep now performs a single conditional update that re-checks status at write time, and it no longer bypasses the state machine.

Related Issue

Closes #

Changes

🔧 Bounty Expiry Fix

  • [MODIFY] src/bounties/bounties.service.ts

    • Replaced the read-then-save loop in expireOverdue() with a single conditional UPDATE that filters on both deadline < now and status IN (OPEN, FUNDED, CLAIMED), so the status check and the write are atomic.
    • Returns the affected row count.
  • [MODIFY] src/bounties/bounty-expiry.scheduler.ts

    • Adjusted the scheduler to consume the affected-count return value from expireOverdue().
  • [MODIFY] src/bounties/bounties.service.spec.ts

    • Added a test where a bounty's status changes between the read and the write (e.g. CLAIMED → IN_REVIEW or MERGED), asserting that it is not moved to EXPIRED.

Verification Results

npm test -- src/bounties/bounties.service.spec.ts
Acceptance Criteria Status
Concurrently advanced bounties are not overwritten to EXPIRED ✅ Conditional update re-checks status at write time
Expiry no longer skips the state machine for an invalid transition ✅ Only OPEN / FUNDED / CLAIMED rows are matched
Paid bounties cannot be flipped to EXPIRED and then refunded ✅ MERGED / PAID rows are excluded by the atomic filter

Closes #460

@vercel

vercel Bot commented Oct 23, 2026

Copy link
Copy Markdown

@Youngthreader is attempting to deploy a commit to the chonilius' projects Team on Vercel.

A member of the Team first needs to authorize it.

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.

BountiesService.expireOverdue() overwrites concurrently-advanced bounties to EXPIRED — read-then-save with no status re-check and no assertTransition

1 participant