Skip to content

miner(attempt): close the two acknowledged .d.ts drifts in AttemptCliResult and RunAttemptOptions #9685

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/attempt-cli.ts carries two type drifts that the code itself flags in comments and works around with casts.

1. A real outcome missing from the exported result union. runAttempt returns exit code 11 with a blockedResult object whose outcome is "blocked_max_concurrent_claims", then does options.onResult?.(blockedResult as AttemptCliResult). AttemptCliResult (lines 98-125) has no such variant. The knock-on is real: loop-cli.ts:76 types the loop's own per-cycle summary field as attemptOutcome?: AttemptCliResult["outcome"] | "attempt_error", so the JSON loop --json emits can carry a value its own exported type says is impossible, and loop-cli.ts:507's permanentBlock/requeue classification cannot be type-checked against it.

This is the exact defect class already fixed once for the sibling variant: closed issue #9331, "ams: attempt-cli's blocked_own_open_pr outcome is missing from the exported AttemptCliResult type", added blocked_own_open_pr (now line 101). blocked_max_concurrent_claims was never given the same treatment.

2. A real injection seam missing from the options type. runAttempt reads its reputation-history loader through a cast onto its own options object:

const readReputationHistory =
  (options as RunAttemptOptions & { loadReputationHistory?: typeof loadReputationHistory }).loadReputationHistory ??
  loadReputationHistory;

RunAttemptOptions (lines 139-186) declares every other seam explicitly (getAttemptHistory, recordOwnSubmission, resolveClaimConflict, ...). A caller reading the public type has no way to know this seam exists.

Requirements

  • Add a blocked_max_concurrent_claims variant to the AttemptCliResult union, carrying exactly the fields blockedResult builds: CommonAttemptResultFields & { outcome: "blocked_max_concurrent_claims"; reason: string; maxConcurrentClaims: number; activeClaimCount: number }.
  • Remove the as AttemptCliResult cast on the options.onResult?.(blockedResult) call and the ".d.ts drift" comment above it.
  • Add loadReputationHistory?: typeof loadReputationHistory; to RunAttemptOptions, placed beside the other resolver seams, with a one-line doc comment matching their style.
  • Remove the inline (options as RunAttemptOptions & { ... }) cast and the ".d.ts drift" comment above it.
  • No runtime behaviour may change: the emitted object's fields, the exit code 11, and the resolution order (options.loadReputationHistory ?? loadReputationHistory) must all be identical.

⚠️ Required pattern: mirror the already-shipped fix for blocked_own_open_pr (packages/loopover-miner/lib/attempt-cli.ts:101) for the union variant, and mirror the neighbouring declared seams such as getAttemptHistory?: typeof GetAttemptHistoryFn; (line 174) for the options field. It does NOT satisfy this issue to widen outcome to string, to leave either cast in place, to introduce a separate BlockedAttemptResult type that is not part of the AttemptCliResult union, or to fix only one of the two drifts.

Deliverables

  • AttemptCliResult includes a blocked_max_concurrent_claims variant with reason, maxConcurrentClaims, and activeClaimCount.
  • The options.onResult?.(blockedResult) call at the max-concurrent-claims block no longer casts, and the ".d.ts drift" comment is gone.
  • RunAttemptOptions declares loadReputationHistory?: typeof loadReputationHistory, the inline cast is gone, and its ".d.ts drift" comment is gone.
  • A new named test in test/unit/miner-attempt-cli.test.ts drives the max-concurrent-claims block (injected claim ledger returning { claimed: false, ... }), captures onResult's argument, and asserts outcome === "blocked_max_concurrent_claims" together with the maxConcurrentClaims and activeClaimCount values and the exit code 11.
  • A new test asserts an injected loadReputationHistory passed through the plain (uncast) RunAttemptOptions is the one actually used.

All Deliverables above are required in a single PR. A PR that satisfies only some of them — for example adding the union variant while leaving the RunAttemptOptions cast in place — does not resolve this issue.

Test Coverage Requirements

packages/loopover-miner/lib/**/*.ts IS inside Codecov's coverage.include in vitest.config.ts, so the 99%+ branch-counted codecov/patch gate applies exactly as for src/**. Both arms of the options.loadReputationHistory ?? loadReputationHistory nullish coalesce need a test (injected and default), and the max-concurrent-claims block must be exercised end to end.

Expected Outcome

AttemptCliResult describes every outcome runAttempt can actually report — so loop --json's attemptOutcome field is type-accurate — and every injection seam runAttempt honours is declared on RunAttemptOptions, with no type assertions left in either path.

Links & Resources

packages/loopover-miner/lib/attempt-cli.ts:98-125, :139-186, :770-778, :817-842, packages/loopover-miner/lib/loop-cli.ts:70-84. Precedent: closed issue #9331.

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