Skip to content

fix(miner): manage-status.js's runManageStatus has no catch, unlike every sibling CLI command #7236

Description

@JSONbored

Context

packages/loopover-miner/lib/manage-status.js's runManageStatus (lines 213-241) opens three local SQLite
stores and then runs its actual work with only a try { ... } finally { ...close... } — there is no
catch clause at all
:

export function runManageStatus(args = [], options = {}) {
  const parsed = parseManageStatusArgs(args);
  if ("error" in parsed) {
    return reportCliFailure(argsWantJson(args), parsed.error);
  }

  const ownsPortfolioQueue = options.initPortfolioQueue === undefined;
  const ownsEventLedger = options.initEventLedger === undefined;
  const ownsRunStateStore = options.initRunStateStore === undefined;
  const portfolioQueue = (options.initPortfolioQueue ?? initPortfolioQueueStore)();
  const eventLedger = (options.initEventLedger ?? initEventLedger)();
  const runStateStore = (options.initRunStateStore ?? initRunStateStore)();
  try {
    const rows = collectManageStatus({ portfolioQueue, eventLedger });
    const runPortfolio = collectRunPortfolio({ portfolioQueue, eventLedger, runStateStore });
    // ...console.log(...)...
    return 0;
  } finally {
    if (ownsPortfolioQueue) portfolioQueue.close();
    if (ownsEventLedger) eventLedger.close();
    if (ownsRunStateStore) runStateStore.close();
  }
}

collectManageStatus/collectRunPortfolio are not pure formatting helpers — they read real store data
(portfolioQueue.listQueue, eventLedger.readEvents, runStateStore.listRunStates) and throw on invalid
input (e.g. collectManageStatus throws invalid_portfolio_queue/invalid_event_ledger when a store
handle is malformed, and a corrupted/locked SQLite file surfaces as a thrown error from the underlying
node:sqlite calls). Because there is no catch, any such failure propagates out of runManageStatus as
an uncaught exception instead of going through this package's structured CLI failure path.

Every other IO-touching CLI command in this package wraps its store reads in try { ... } catch (error) { return reportCliFailure(...) }, confirmed by grepping lib/*-cli.jsattempt-cli.js, discover-cli.js,
loop-cli.js, portfolio-queue-cli.js, claim-ledger-cli.js, governor-ledger-cli.js,
governor-metrics-cli.js, event-ledger-cli.js, plan-store-cli.js, migrate-cli.js, and
orb-export.js's runOrbExportCli all catch and report via reportCliFailure(wantsJson, message, exitCode), which defaults exitCode to 2 (packages/loopover-miner/lib/cli-error.js). manage-status.js
is the one outlier — confirmed by grepping every lib/*-cli.js file for try { vs } catch counts, where
manage-status.js is the only file with try=1 catch=0.

The practical effect: loopover-miner manage status on a corrupted/locked local store crashes as an
unhandled exception (caught only by process-lifecycle.js's global uncaughtException handler, which logs
and exits with code 1) instead of the package's own structured failure output ({ ok: false, error } on
--json, or a clean stderr message) at exit code 2 — the same convention every sibling command already
follows.

Requirements

  • runManageStatus in packages/loopover-miner/lib/manage-status.js must wrap the collectManageStatus
    / collectRunPortfolio call site (and the subsequent console.log) in a try { ... } catch (error) { return reportCliFailure(parsed.json, describeCliError(error)); } block, matching the exact pattern
    already used by runOrbExportCli (lib/orb-export.js) and runQueueList (lib/portfolio-queue-cli.js):
    the store-opening lines stay outside the try, the catch sits between the existing try body and the
    existing finally block (do not remove or reorder the finally's store-closing logic).
  • Import describeCliError alongside the existing argsWantJson, reportCliFailure import from
    ./cli-error.js (it is not currently imported in this file).
  • Do not change collectManageStatus/collectRunPortfolio's own throwing behavior, and do not add a
    catch anywhere else in this file (e.g. parseManageStatusArgs has no IO and needs none).
  • The fix is scoped to packages/loopover-miner/lib/manage-status.js only.

Deliverables

  • runManageStatus catches any error thrown while collecting/rendering manage status and reports it via
    reportCliFailure(parsed.json, describeCliError(error)) (exit code 2, matching every sibling CLI
    command), instead of letting it propagate as an unhandled exception.
  • The existing finally block (closing portfolioQueue/eventLedger/runStateStore when owned) is
    preserved unchanged.
  • A regression test (in this package's existing miner-manage-status test suite) that stubs
    initPortfolioQueue/initEventLedger/initRunStateStore so collectManageStatus or
    collectRunPortfolio throws, and asserts runManageStatus returns 2 (not an uncaught exception) with
    the expected reportCliFailure-shaped output on both the --json and plain-text paths.

Test Coverage Requirements

This repo's Codecov patch gate (codecov/patch) enforces target: 99%, threshold: 0%, branch-counted, on
every changed line/branch under src/**/packages/** — this fix is squarely inside packages/** and is
gated. Add the regression test described above (covering the new catch branch, both --json and
plain-text failure rendering) so the new branch is exercised, not just the existing happy path. Measure
locally with npm run test:coverage (unsharded), per this repo's coverage-measurement convention.

Expected Outcome

loopover-miner manage status on a failing/corrupted local store returns exit code 2 with a
reportCliFailure-shaped error (JSON { ok: false, error } under --json, plain stderr text otherwise),
identical in shape and exit-code convention to every other IO-touching subcommand in this package, instead of
crashing as an unhandled exception.

Links & Resources

  • packages/loopover-miner/lib/manage-status.js (the file to fix — runManageStatus, lines ~213-241)
  • packages/loopover-miner/lib/cli-error.js (reportCliFailure's default exitCode = 2, describeCliError)
  • packages/loopover-miner/lib/orb-export.js's runOrbExportCli and packages/loopover-miner/lib/portfolio-queue-cli.js's withPortfolioQueue-wrapped commands for the established try/catch/finally pattern to mirror

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