Skip to content

miner(queue): queue dashboard is the only queue subcommand with no error handling #9690

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

runQueueCli (packages/loopover-miner/lib/portfolio-queue-cli.ts:623-640) dispatches eight subcommands. Seven of them handle a store failure identically, e.g. runQueueList:

try {
  return withPortfolioQueue(options, (portfolioQueue) => { ... });
} catch (error) {
  return reportCliFailure(parsed.json, describeCliError(error));
}

queue dashboard is the outlier. runPortfolioDashboard in packages/loopover-miner/lib/portfolio-dashboard.ts opens the store and calls the collector with only a finally:

const portfolioQueue = (options.initPortfolioQueue ?? initPortfolioQueueStore)();
try {
  const summary = collectPortfolioDashboard({ portfolioQueue }, { nowMs: ... });
  console.log(parsed.json ? JSON.stringify(summary, null, 2) : renderPortfolioDashboardTable(summary));
  return 0;
} finally {
  if (ownsQueue) portfolioQueue.close();
}

It also does not import describeCliError (only argsWantJson and reportCliFailure, line 11), and the store open itself sits outside the try entirely — so an initPortfolioQueueStore() failure (a corrupted portfolio-queue.sqlite3, an unreadable state dir, an invalid LOOPOVER_MINER_PORTFOLIO_QUEUE_DB) propagates out of runQueueCli, out of bin/loopover-miner.ts:124's process.exit(runQueueCli(...)), and terminates the CLI with a raw Node stack trace and exit code 1 — where every sibling queue subcommand prints { "ok": false, "error": ... } under --json and exits 2.

collectPortfolioDashboard throws invalid_portfolio_queue by design (line 59), and initPortfolioQueueStore throws invalid_portfolio_queue_db_path — both are unreachable as clean CLI errors today.

Requirements

  • Move the store construction inside the try in runPortfolioDashboard, so an opener failure is handled rather than propagated.
  • Add a catch (error) { return reportCliFailure(parsed.json, describeCliError(error)); } to runPortfolioDashboard, matching runQueueList's shape exactly.
  • Import describeCliError from ./cli-error.js.
  • Guard the finally close with ?. (the store variable may be unassigned when the opener threw), matching runQueueClaimBatch's own finally { if (ownsManager) manager?.close(); } (portfolio-queue-cli.ts:538-540).
  • The success path, the parse-error path, and the ownsQueue ownership rule must be unchanged.

⚠️ Required pattern: mirror runQueueClaimBatch in packages/loopover-miner/lib/portfolio-queue-cli.ts:520-541 — open inside the try, catch into reportCliFailure(parsed.json, describeCliError(error)), finally closes with ?.. It does NOT satisfy this issue to add a try/catch in runQueueCli's dispatcher instead (that would change the error shape for all eight subcommands), to catch and return 0, or to leave the opener outside the try.

Deliverables

  • runPortfolioDashboard constructs the store inside its try, has a catch returning reportCliFailure(parsed.json, describeCliError(error)), and closes with ?. in finally.
  • A new named regression test in test/unit/miner-portfolio-dashboard.test.ts injects an initPortfolioQueue that throws and asserts runPortfolioDashboard([], options) returns 2 (today it throws).
  • A second case asserts the same with --json, and that stdout received {"ok": false, "error": ...}.
  • A third case asserts a store whose listQueue throws mid-run still closes the store and returns 2.

All Deliverables above are required in a single PR. A PR that satisfies only some of them — for example adding the catch while leaving the opener outside the try, so an opener failure still escapes — 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 new catch need a test (success and failure), both arms of parsed.json on the failure path, and both arms of the ownsQueue / ?. close. The failure cases must be named regression tests that fail against the current code.

Expected Outcome

loopover-miner queue dashboard reports a corrupted or unopenable portfolio-queue store the same way every other queue subcommand does — exit 2, { ok: false, error } under --json — instead of crashing with an uncaught stack trace.

Links & Resources

packages/loopover-miner/lib/portfolio-dashboard.ts:140-164, packages/loopover-miner/lib/portfolio-queue-cli.ts:292-311, :520-541, packages/loopover-miner/lib/cli-error.ts.

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