diff options
Diffstat (limited to '.rules/plan/11-15-errors-module.md')
| -rw-r--r-- | .rules/plan/11-15-errors-module.md | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/.rules/plan/11-15-errors-module.md b/.rules/plan/11-15-errors-module.md new file mode 100644 index 0000000..7a11798 --- /dev/null +++ b/.rules/plan/11-15-errors-module.md @@ -0,0 +1,123 @@ +# Phase 11 — Errors module rename and retarget + +**Estimated time:** ~15 minutes +**Touches:** `lib/dispatch/adapter/minimax/errors.rb` and every file +that references `ClaudeErrors` or `OverloadedError`. + +## Goal + +The errors module is currently `Dispatch::Adapter::ClaudeErrors`. +Rename it to `Dispatch::Adapter::MiniMaxErrors`. The mapping logic +(401/403 → AuthenticationError, 429 → RateLimitError, 529 → +OverloadedError, 400/422 → RequestError, 5xx → ServerError) stays the +same. Update the `PROVIDER` constant. + +The class `OverloadedError < RateLimitError` stays — Anthropic uses 529 +to signal overload and MiniMax MAY too; even if MiniMax never sends +529, the class is harmless dead branch coverage. + +## Steps + +### 1. Rewrite `lib/dispatch/adapter/minimax/errors.rb` + +```ruby +# frozen_string_literal: true + +module Dispatch + module Adapter + class OverloadedError < RateLimitError; end + + module MiniMaxErrors + module_function + + PROVIDER = "MiniMax" + + def handle_response!(response) + return if response.is_a?(Net::HTTPSuccess) + + code = response.code.to_i + msg = parse_message(response.body) + retry_after = response["Retry-After"]&.to_i + + case code + when 401, 403 then raise AuthenticationError.new(msg, status_code: code, provider: PROVIDER) + when 429 then raise RateLimitError.new(msg, status_code: code, provider: PROVIDER, retry_after:) + when 529 then raise OverloadedError.new(msg, status_code: code, provider: PROVIDER, retry_after:) + when 400, 422 then raise RequestError.new(msg, status_code: code, provider: PROVIDER) + when 500..599 then raise ServerError.new(msg, status_code: code, provider: PROVIDER) + else raise Error.new(msg, status_code: code, provider: PROVIDER) + end + end + + def parse_message(body) + parsed = JSON.parse(body.to_s) + # Anthropic shape: {"error":{"message":"..."}} + # MiniMax may also use the same shape; keep the dig. + return parsed.dig("error", "message").to_s unless parsed.dig("error", "message").nil? + # Fallback: top-level "message" key (some MiniMax surfaces use this). + return parsed["message"].to_s if parsed["message"] + body.to_s + rescue JSON::ParserError + body.to_s + end + end + end +end +``` + +Notes on `parse_message`: + +- Adds a fallback for a top-level `"message"` key. We don't yet know + MiniMax's exact error JSON shape, but supporting both `{error:{message}}` + and `{message}` is cheap and forwards-compatible. +- If neither matches, falls back to the raw body. + +### 2. Find every reference to `ClaudeErrors` and update + +```bash +grep -rn 'ClaudeErrors\|ClaudeErrors::PROVIDER' lib/ spec/ sig/ +``` + +Replace each occurrence with `MiniMaxErrors`. Common locations: +- `lib/dispatch/adapter/minimax/sse_parser.rb` + (`raise RequestError.new(..., provider: ClaudeErrors::PROVIDER)`) +- `lib/dispatch/adapter/minimax/http_client.rb` +- `lib/dispatch/adapter/minimax/stream_collector.rb` +- `lib/dispatch/adapter/minimax/usage_client.rb` — DELETED in phase 02, + shouldn't appear, but double-check. +- `lib/dispatch/adapter/minimax.rb` (top-level adapter) + +Also confirm the rbs sig file mirrors the rename: + +```bash +grep -n 'ClaudeErrors' sig/dispatch/adapter/minimax.rbs +``` + +If there's a sig declaration for `ClaudeErrors`, rename to +`MiniMaxErrors`. + +### 3. Confirm `errors.rb` is required + +`lib/dispatch/adapter/minimax.rb` should have +`require_relative "minimax/errors"` near the top of its requires list. +If phase 01 left it as `require_relative "minimax/errors"` already, no +change needed. The new module name `MiniMaxErrors` is autoloaded via +that file. + +## Acceptance criteria + +- `grep -rn 'ClaudeErrors' lib/ spec/ sig/` returns ZERO matches. +- `Dispatch::Adapter::MiniMaxErrors::PROVIDER == "MiniMax"`. +- `Dispatch::Adapter::MiniMaxErrors.handle_response!(...)` raises the + correct mapped error class for each status code as documented above. +- `parse_message('{"error":{"message":"oops"}}') == "oops"`. +- `parse_message('{"message":"oops"}') == "oops"`. +- `parse_message("not json") == "not json"`. +- `bundle exec rubocop --autocorrect-all` exits 0. + +## Verification + +Run `run_tests` with `project_path=reference/dispatch-adapter-minimax`. +Rubocop must be clean. `errors_spec.rb` failures referencing +`ClaudeErrors` are addressed in phase 16. Failures NOT explainable by +that rename must be fixed before calling `ask_for_next_plan`. |
