Skip to content

Claimed recommendations never expire abandoned claims permanently lock users out of the claim limit #172

@Siddhartha-singh01

Description

@Siddhartha-singh01

What happened?

The recsExpire cron in src/inngest/functions/maintenance.ts expires stale
recommendations, but its query filters .eq('status', 'open') so it only ever
expires open recommendations. A recommendation in claimed status is never
expired, no matter how long ago its expires_at passed.

claimRecommendation in src/app/actions/recommendations.ts enforces a 3-claim
limit by counting every status = 'claimed' row for the user, with no expires_at
filter. So once a contributor claims 3 recommendations and abandons them, those
claims count against the limit forever claimRecommendation permanently returns
claim_limit, and the contributor can never claim new work again.

The expires_at window (7 days) is meant to auto-recover abandoned claims, but it
is only enforced for open recs, so it never fires for claimed ones.

Steps to Reproduce

  1. As a contributor, claim 3 recommendations (claimRecommendation).
  2. Do not act on them. Wait until their expires_at passes (or set it in the past).
  3. Let the hourly recsExpire cron run.
  4. Try to claim a 4th recommendation.

Expected Behavior

the abandoned claims past expires_at are released/expired, freeing
the claim slots, so a new claim succeeds.
Actual: the claimed recs are untouched, still count toward the limit, and
claimRecommendation returns claim_limit permanently.

Where does this occur?

Other

Environment

Not environment-specific this is a logic gap in the recsExpire cron in
src/inngest/functions/maintenance.ts, reproducible on any OS / Node version.
No browser involved Inngest background job.

Screenshots / Logs

No error log this is a silent lifecycle gap, shown by the code itself.

recsExpire only expires open recommendations (src/inngest/functions/maintenance.ts):

await sb.from('recommendations')
  .update({ status: 'expired' })
  .lt('expires_at', now)
  .eq('status', 'open')   // claimed recs are never expired
  .select('id');

But claimRecommendation counts every claimed row toward the limit, with no
expires_at filter (src/app/actions/recommendations.ts):

.eq('user_id', user.id)
.eq('status', 'claimed');
if ((claimedCount ?? 0) >= 3) return err('claim_limit', ...);

So a claimed rec past its expires_at is never released, keeps counting toward the
3-claim limit forever, and the contributor is permanently locked out of claiming
new work.

Metadata

Metadata

Assignees

Labels

GSSOC26GirlScript Summer of Code 2026backendBackend / API / DB relatedbugSomething isn't workinghelp wantedExtra attention is neededlevel:advancedAdvanced level difficulty

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions