Skip to content

Cut v0.4.0#11

Merged
jramos merged 5 commits into
developfrom
release/v0.4.0
Apr 25, 2026
Merged

Cut v0.4.0#11
jramos merged 5 commits into
developfrom
release/v0.4.0

Conversation

@jramos
Copy link
Copy Markdown
Owner

@jramos jramos commented Apr 25, 2026

Release the [Unreleased] work since v0.3.0 so cgminer_manager v1.6.0 can depend on the on_wire: kwarg via the closure-based wiring pattern.

Highlights

  • on_wire: kwarg on Miner#initialize / MinerPool#initialize for wire-level telemetry hooks
  • -v / --verbose CLI flag with addpool/setconfig/ascset/pgaset password redaction
  • Structured ApiError: #cgminer_code (Integer) + #code (Symbol) + CGMINER_CODES map (14, 45)
  • AccessDeniedError subclass + ApiError.for_status factory
  • Constructor input validation: ArgumentError on non-Integer cgminer_code:, non-Symbol/non-String code:
  • MinerPool#load_miners! raises CgminerApiClient::Error (was RuntimeError) on missing miners.yml
  • docs/logging.md silent-by-design stub
  • bundle-audit + Dependabot in CI
  • cgminer_test_support extraction (FakeCgminer + Fixtures moved to shared gem)

Required by cgminer_manager v1.6.0 — the trace-id propagation work threads request_id into per-request Miner instances via on_wire:.

Test plan

jramos added 5 commits April 25, 2026 09:41
ApiError subclass for cgminer's "access denied" response (STATUS=E
Code 45) and the gem's own access_denied? local guard. Inherits
from ApiError so existing `rescue ApiError` clauses still catch
it; callers wanting finer dispatch use `rescue AccessDeniedError`
instead of pattern-matching on `e.code == :access_denied`.

  - lib/cgminer_api_client/errors.rb: new AccessDeniedError class.
    Constructor pins code: :access_denied so the symbolic tag is
    consistent regardless of which call site raised. Also adds
    ApiError.for_status — factory used by the wire-side emission
    point that picks AccessDeniedError when the cgminer integer
    maps to :access_denied, falling back to ApiError otherwise.

  - lib/cgminer_api_client/miner.rb: check_status now delegates to
    ApiError.for_status. Removes the inline Integer coercion and
    class-picking from the case statement.

  - lib/cgminer_api_client/miner/commands.rb: access_denied? raises
    AccessDeniedError directly (legacy raise(class, message) form,
    cgminer_code stays nil because privileged's rescue dropped it).

  - Tests: dedicated access_denied_error_spec.rb covers class
    hierarchy + constructor + rescue dispatch (subclass, ApiError,
    Error). api_error_spec.rb gains .for_status coverage including
    the String-Code defensive coercion. Existing emission-site
    tests in miner_spec.rb, commands_spec.rb, and the wire-side
    integration test extended to assert the subclass type.

Tests: 258 → 276 examples (+18). Rubocop clean. Coverage 99.7%.
ApiError.new("msg", code: 42) previously raised NoMethodError on
.to_sym deep in the constructor — opaque failure mode. code: false
silently bypassed to map lookup because false || x evaluates to x.
Both rejected at the library boundary now with a clear ArgumentError.

Symbol and String forms still work (the to_sym coercion stays for
ergonomic callers); nil still falls through to map lookup or
:unknown. Seven new tests pin the boundaries (Integer, Hash, Array,
false rejected; Symbol, String, nil accepted).

Tests: 276 → 283 examples (+7). Rubocop clean. Coverage 99.7%.
The fatal-status test asserts that an unmapped cgminer Code falls
through to code: :unknown — but the assertion silently degrades if
a future PR maps 23 to a symbol (the test would still pass, but
exercise the mapped path while claiming to test the fallback).

A precondition example asserting CGMINER_CODES has no key for 23
trips loudly the moment 23 gets mapped, so the unmapped fixture
gets updated alongside the map change.
CHANGELOG:
  - New [Unreleased] ### Added entry for AccessDeniedError +
    ApiError.for_status factory.
  - Existing structured-codes entry updated with the e.code-not-
    e.cgminer_code dispatch advisory and the corrected mechanism
    description (privileged hits the wire and discards the integer
    in its rescue, rather than the previously stated "before any
    wire interaction").
  - New [Unreleased] ### Changed entry for the constructor's
    Integer/Symbol-or-String input validation.
  - Drops the "real cgminer 4.11.1 fixtures" version pin in favor
    of "real cgminer wire fixtures" — the version isn't
    load-bearing for the claim and would date when fixtures
    refresh against a newer cgminer.

AGENTS.md:
  - errors.rb tree-line picks up AccessDeniedError.
  - Error-handling section gains the dispatch advisory ("prefer
    e.code over e.cgminer_code") and a paragraph naming
    AccessDeniedError + the asymmetry rule for adding new
    ApiError subclasses (only when a code earns enough dispatch-
    site interest).
  - Same version-pin removal as the CHANGELOG.
  - New paragraph names ApiError.for_status as the wire-side
    factory and notes that non-wire paths raise the right class
    directly rather than going through the factory.
Releases the Unreleased work accumulated since v0.3.0:

  * on_wire: kwarg on Miner#initialize and MinerPool#initialize
  * -v / --verbose flag on the bin/cgminer_api_client CLI with
    addpool/setconfig/ascset/pgaset password redaction
  * Structured cgminer_code (Integer) + code (Symbol) fields on
    ApiError; CGMINER_CODES map (14, 45)
  * AccessDeniedError < ApiError subclass + ApiError.for_status
    factory for the most-dispatched-on case
  * Constructor input validation: cgminer_code: Integer-or-nil,
    code: Symbol/String-or-nil; ArgumentError on bad input
  * MinerPool#load_miners! raises CgminerApiClient::Error (was
    RuntimeError) when config/miners.yml is missing
  * docs/logging.md silent-by-design stub + bundle-audit + Dependabot
  * cgminer_test_support extraction (FakeCgminer + Fixtures)

Required by cgminer_manager v1.6.0 trace-id propagation work, which
threads request_id into per-request Miner instances via the on_wire:
closure pattern.
@jramos jramos merged commit 64ac716 into develop Apr 25, 2026
6 checks passed
@jramos jramos deleted the release/v0.4.0 branch April 25, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant