Skip to content

miner(claim-ledger): claimIssueWithinCap wrongly rejects an idempotent re-claim of an already-active issue once the repo is at cap #10342

Description

@JSONbored

⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.

Context

packages/loopover-miner/lib/claim-ledger.ts's recordClaim uses a single atomic
INSERT ... ON CONFLICT ... DO UPDATE ... WHERE miner_claims.status <> 'active' statement (around
lines 224-233), deliberately designed so that re-recording a claim for an issue that is ALREADY
actively claimed is a true no-op — its own comment says so explicitly: "The WHERE status <> 'active' guard makes re-claiming an already-active issue a true no-op (no row churn), never a
duplicate row."

claimIssueWithinCap (around lines 341-370), the concurrency-capped wrapper attempt-cli.ts
actually calls, never reaches that no-op logic for a same-issue re-claim once the repo is at its
concurrency cap — the cap check runs FIRST, unconditionally, before any check of whether the
specific (repoFullName, issueNumber) pair is the SAME claim already active:

const activeClaimCount = (countActiveRepoStatement.get(normalizedRepo) as CountRow).count;
if (activeClaimCount >= cap) {
  db.exec("COMMIT");
  return { claimed: false, claim: null, activeClaimCount, maxConcurrentClaims: cap };
}
const claim = ledger.recordClaim({ repoFullName, issueNumber, note, apiBaseUrl } as RecordClaimInput);

Reproduction: with cap = 1, claim issue #1 in a repo (activeClaimCount 0 → 1). Call
claimIssueWithinCap again for the SAME issue #1 in the SAME repo: activeClaimCount is now 1,
1 >= cap(1) is true, so the function returns { claimed: false, ... } — even though
recordClaim's own WHERE status <> 'active' guard would have made re-recording issue #1 a
genuine no-op that never increases the active count, and even though the repo is not actually over
capacity in any real sense (the "new" claim IS the claim already counted).

This is directly reachable via this module's own documented crash-recovery path:
attempt-cli.ts (lines ~791-825) calls claimIssueWithinCap per attempt and only releases the
claim in a finally block on a terminal outcome — a hard process kill mid-attempt leaves the claim
row active (until the ledger's DEFAULT_MAX_CLAIM_AGE_MS sweep expires it, up to 14 days later).
A retry of the SAME issue while its repo sits at cap is incorrectly rejected as
max_concurrent_claims_exceeded, even though resuming/re-affirming its own already-active claim
should succeed.

test/unit/miner-claim-ledger.test.ts's describe("claimIssueWithinCap...") block (lines
~543-631) tests under-cap claims, at-cap rejection of a DIFFERENT issue, per-repo isolation,
cross-process racing, and sweep-then-claim — but never tests re-claiming the SAME (repo, issue)
pair while already at cap.

Requirements

  • In claimIssueWithinCap, check whether an existing ACTIVE claim row already exists for the exact
    (repoFullName, issueNumber) pair being claimed BEFORE applying the cap gate. If one exists,
    proceed to call recordClaim (which will correctly no-op via its own WHERE status <> 'active'
    guard) regardless of the current activeClaimCount relative to cap — do not reject a same-
    issue re-claim as over-cap.
  • For any OTHER issue (a genuinely new claim, or a claim on a different issue number), the existing
    cap-gate behavior must be unchanged — this issue only fixes the same-issue-re-claim case, not the
    cap enforcement itself.
  • Keep the fix inside the existing single BEGIN IMMEDIATE transaction — do not introduce a second
    transaction or a read outside the lock that could reintroduce the race the function's own comment
    says the current design closes.

Deliverables

  • claimIssueWithinCap no longer rejects a re-claim of an issue that is already the caller's
    own active claim, even when the repo's active-claim count equals or exceeds cap.
  • claimIssueWithinCap still correctly rejects a claim for a DIFFERENT issue once the repo is
    at cap (the pre-existing, still-required behavior).
  • A new regression test asserting that claiming issue feat(docs): add install site and mcp diagnostics #1 at cap = 1, then calling
    claimIssueWithinCap again for the SAME issue feat(docs): add install site and mcp diagnostics #1 in the same repo, returns
    { claimed: true, ... } (or the equivalent success shape reflecting the no-op re-affirm),
    not { claimed: false, ... }.
  • A new regression test asserting that, in the same at-cap scenario, claiming a DIFFERENT issue
    chore(release): prepare public gittensory launch #2 in the same repo still correctly returns { claimed: false, ... } — guarding against an
    overly-broad fix that accidentally lets any claim through once one active claim exists.

Both regression tests and the fix are required in this single PR.

Test Coverage Requirements

This repo's Codecov patch gate is 99%+ (branch-counted) on packages/loopover-miner/lib/**. Add
the new regression tests to test/unit/miner-claim-ledger.test.ts, inside or alongside the
existing describe("claimIssueWithinCap...") block (this package's tests live in the shared root
test/ directory, not packages/loopover-miner/test/**). The new same-issue-existing-active-claim
branch must be exercised, along with the pre-existing different-issue-at-cap rejection branch
remaining covered.

Expected Outcome

A miner process that crashes mid-attempt and is retried against the SAME issue can successfully
re-affirm its own already-active claim even when the repo is at its concurrency cap — matching
recordClaim's own documented idempotent-re-claim guarantee, which claimIssueWithinCap currently
defeats for exactly the crash-recovery scenario the claim ledger exists to support.

Links & Resources

  • packages/loopover-miner/lib/claim-ledger.tsrecordClaim (~lines 224-233),
    claimIssueWithinCap (~lines 341-370).
  • packages/loopover-miner/lib/attempt-cli.ts — the crash-recovery-relevant caller (~lines
    791-825).
  • test/unit/miner-claim-ledger.test.ts — the existing claimIssueWithinCap test block (~lines
    543-631) to extend.

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions