Skip to content

feat(miner): add a claim reclaim CLI to expire orphaned soft-claims - #9717

Merged
JSONbored merged 1 commit into
JSONbored:mainfrom
shin-core:feat/miner-claim-reclaim-cli-9686
Jul 29, 2026
Merged

feat(miner): add a claim reclaim CLI to expire orphaned soft-claims#9717
JSONbored merged 1 commit into
JSONbored:mainfrom
shin-core:feat/miner-claim-reclaim-cli-9686

Conversation

@shin-core

Copy link
Copy Markdown
Contributor

What & why

Closes #9686.

ClaimLedger.reclaimExpiredClaims(maxAgeMs?) exists to expire claims orphaned by a crashed/killed
attempt, but had no production caller — unlike its named model reclaimStuckItems, which both
runs automatically inside claimNextBatch and has an operator escape hatch (loopover-miner queue release). A claim stranded active by a SIGKILLed attempt therefore counts against that repo's
maxConcurrentClaims cap for up to the 14-day DEFAULT_MAX_CLAIM_AGE_MS window, with no command an
operator can run to clear it.

Change

Add loopover-miner claim reclaim [--max-age-ms <n>] [--dry-run] [--json], mirroring runQueueRelease
(portfolio-queue-cli.ts) exactly — same parse → dry-run short-circuit → withClaimLedger → reportCliFailure(describeCliError(error)) structure:

  • Calls ClaimLedger.reclaimExpiredClaims(maxAgeMs), passing --max-age-ms when supplied and omitting
    it so the ledger's own DEFAULT_MAX_CLAIM_AGE_MS default applies.
  • --max-age-ms accepts only a finite integer >= 0; anything else returns the subcommand usage
    string via reportCliFailure.
  • --dry-run prints what would be reclaimed and returns 0 without opening the claim ledger.
  • --json prints { "reclaimed": [...] }; plain text prints one line per reclaimed claim plus a
    count, or none. Exit 0 either way — reclaiming nothing is not a failure.
  • Registered in runClaimCli's dispatch and in printHelp alongside claim/release/list.

Validation

  • New tests cover every new branch: --max-age-ms supplied/omitted, valid/invalid
    (fractional/negative/non-numeric/missing), --dry-run on/off (asserting the ledger is never
    opened
    via an injected opener spy), --json on/off, reclaimed-empty/nonempty, an explicit smaller
    window reclaiming a claim inside the default window, the ledger-error path, and dispatcher
    reachability of runClaimCli("reclaim", …).
  • Bug-catch verified: removing the dispatch registration fails the reclaim-dispatch test.
  • 100% patch coverage on every changed line and branch of claim-ledger-cli.ts and cli.ts.

ClaimLedger.reclaimExpiredClaims existed to expire claims stranded active by a
crashed/killed attempt, but had no production caller -- unlike its named model
reclaimStuckItems, which both runs automatically inside claimNextBatch AND has an
operator escape hatch (`queue release`). A claim left active by a SIGKILLed attempt
therefore counts against the repo's maxConcurrentClaims cap for up to the 14-day
default window, with no command to clear it.

Add `loopover-miner claim reclaim [--max-age-ms <n>] [--dry-run] [--json]`,
mirroring runQueueRelease's parse -> dry-run-short-circuit -> withStore ->
reportCliFailure shape:

- Calls ClaimLedger.reclaimExpiredClaims(maxAgeMs), passing --max-age-ms when
  supplied and omitting it so the ledger's own DEFAULT_MAX_CLAIM_AGE_MS applies.
- --max-age-ms accepts only a finite integer >= 0; anything else returns usage.
- --dry-run prints what would be reclaimed and returns 0 without opening the ledger.
- --json prints { "reclaimed": [...] }; plain text prints one line per reclaimed
  claim plus a count, or `none`. Exit 0 either way -- reclaiming nothing is not a
  failure.
- Registered in runClaimCli's dispatch and printHelp alongside claim/release/list.

Tests cover every new branch: max-age supplied/omitted, valid/invalid, dry-run
on/off (asserting the ledger is never opened via an injected opener), json on/off,
reclaimed-empty/nonempty, and dispatcher reachability.

Closes JSONbored#9686
@shin-core
shin-core requested a review from JSONbored as a code owner July 29, 2026 04:25
@superagent-security

Copy link
Copy Markdown
Contributor

🚨 Contributor flagged. Click here for more info: Superagent Dashboard

@superagent-security superagent-security Bot added the contributor:flagged Contributor flagged for review by trust analysis. label Jul 29, 2026
@loopover-orb

loopover-orb Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Warning

⏸️ LoopOver review result - manual review recommended

Review updated: 2026-07-29 04:41:50 UTC

3 files · 1 AI reviewer · no blockers · CI green · unstable

⏸️ Suggested Action - Manual Review

Review summary
This PR adds a `claim reclaim` CLI subcommand that mirrors the existing `runQueueRelease` structure exactly, wiring the previously-uncalled `ClaimLedger.reclaimExpiredClaims` into an operator-facing command. The implementation is correct: arg parsing validates `--max-age-ms` as a non-negative integer, `--dry-run` short-circuits before opening the ledger (verified by an injected-spy test), and the dispatcher registration in `runClaimCli` plus help text in `cli.ts` are both present and tested. Test coverage is thorough, covering every parse branch, both dry-run text/JSON arms, the omitted-vs-explicit `maxAgeMs` ternary, and the ledger-error path.

Nits — 4 non-blocking
  • packages/loopover-miner/lib/claim-ledger-cli.ts:426-445 — the reported 'console' debug-leftover flags are false positives here; these are the intentional `console.log`/`console.error` output calls the CLI is supposed to produce (matching every other subcommand's convention), not debug leftovers.
  • The external brief's 'deep nesting depth 5' and 'long file 460 lines' flags are marginal — the new `runClaimReclaim`/`parseClaimReclaimArgs` functions themselves are short and match the existing file's control-flow shape (same nesting pattern as `runClaimClaim`/`runClaimRelease`); consider extracting the `--max-age-ms` parsing loop only if this file keeps growing with new subcommands.
  • packages/loopover-miner/lib/claim-ledger-cli.ts: `--max-age-ms` rejects `Infinity`/`NaN` via `Number.isInteger`, which is correct, but there's no upper bound — an operator could pass an absurdly large value; this is a minor operator-input hardening point, not a real risk since it only widens (not narrows) the reclaim window.
  • Nothing structural to change — the mirroring of `runQueueRelease`'s parse → dry-run → withClaimLedger → reportCliFailure shape is exactly the right pattern to reuse per repo#… convention, and the tests are appropriately targeted at the real branches (including the `reclaimed.length === 0` vs nonempty text-output arms).

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #9686
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ❌ 5/25 Preflight is holding this PR: the review lane is unavailable, so it is not ready for automated review.
Contributor workload ✅ 10/10 Author activity: 36 registered-repo PR(s), 25 merged, 0 issue(s).
Contributor context ✅ Confirmed Gittensor contributor shin-core; Gittensor profile; 36 PR(s), 0 issue(s).
Improvement ✅ Minor risk: clean · value: minor
Linked issue satisfaction

Addressed
The diff adds parseClaimReclaimArgs/runClaimReclaim mirroring runQueueRelease's parse -> dry-run short-circuit -> withClaimLedger -> reportCliFailure structure, registers it in runClaimCli's dispatch, adds the printHelp line, and includes tests covering over-age/none-over-age reclaim, explicit --max-age-ms window, invalid args, dry-run without opening the ledger, JSON/plain output, error path, and

Review context
  • Author: shin-core
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is registered but has no active allocation in the current snapshot.
  • Public profile languages: TypeScript, JavaScript, Solidity, Dart, Python, CSS, PHP, Rust
  • Official Gittensor activity: 36 PR(s), 0 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Await review-lane availability.
  • Then work through the remaining 1 step in the Signals table above.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

Decision record
  • action: hold · clause: success
  • config: bd99640b0586dfd884ff8880cb3222bdd11fafd99c2f92fddd4ee404946ee9ac · pack: oss-anti-slop · ci: passed
  • record: b0fc8dcb2a6d8294fd4f0f171f5926cb9ee55aea654dc166b1786ca9e99796a5 (schema v5, head 04b934a)

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.60%. Comparing base (3200abc) to head (04b934a).

Additional details and impacted files
@@             Coverage Diff             @@
##             main    #9717       +/-   ##
===========================================
- Coverage   90.24%   76.60%   -13.64%     
===========================================
  Files         900      284      -616     
  Lines      112914    59609    -53305     
  Branches    26776     8534    -18242     
===========================================
- Hits       101896    45665    -56231     
- Misses       9687    13661     +3974     
+ Partials     1331      283     -1048     
Flag Coverage Δ
backend 99.56% <100.00%> (+4.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/loopover-miner/lib/claim-ledger-cli.ts 100.00% <100.00%> (ø)
packages/loopover-miner/lib/cli.ts 87.50% <ø> (ø)

... and 751 files with indirect coverage changes

@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 29, 2026
@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 29, 2026
@loopover-orb

loopover-orb Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Held for manual review: the gate and required CI are green, but GitHub reports this pull request's mergeable state as unstable because a non-required check or status is not passing, so LoopOver will not auto-merge. A maintainer can resolve the failing check or review and merge manually. This is an automated maintenance action.

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

Labels

contributor:flagged Contributor flagged for review by trust analysis. gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. manual-review Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

miner(claim): wire reclaimExpiredClaims to a real CLI — it has zero production callers

2 participants