# Phase 10 — Broaden strict-tool-schema fallback regex

**Estimated time:** ~10 minutes
**Touches:** `lib/dispatch/adapter/minimax.rb`
(specifically `strict_grammar_error?`).

## Goal

The Claude adapter retries a failed tool-using request with `strict:
false` on tool definitions when Anthropic returns a 400 error like
`"compiled grammar too large"` or `"schema too complex"`. The retry
harness (`chat_streaming_with_strict_fallback`,
`chat_non_streaming_with_strict_fallback`, the `@strict_disabled` flag)
should be KEPT — it is harmless when not triggered and useful when it
is.

The matcher itself, currently keyed on Anthropic's exact wording,
should be broadened so that an analogous MiniMax error message also
fires the fallback. We don't yet know MiniMax's exact wording for this
class of error (or whether they have one), so the new regex must be
tolerant: match HTTP 400 responses whose error message mentions
`grammar` or `schema` and a "too large" / "too complex" / "invalid"
qualifier — case insensitive.

## Steps

### 1. Locate the matcher

Find `def strict_grammar_error?` (or similarly named — search for
`grammar` in `lib/dispatch/adapter/minimax.rb`). It currently looks
like:

```ruby
def strict_grammar_error?(err)
  return false unless err.is_a?(RequestError)
  return false unless err.status_code == 400
  msg = err.message.to_s
  msg.match?(/compiled grammar too large/i) ||
    msg.match?(/schema too complex/i)
end
```

### 2. Broaden the regex

Replace the body with a more tolerant matcher:

```ruby
STRICT_GRAMMAR_PATTERNS = [
  /compiled\s+grammar\s+too\s+large/i,
  /schema\s+too\s+complex/i,
  /(?:grammar|schema).*?(?:too\s*(?:large|complex|big)|invalid|exceed)/i,
  /tool[_\s-]?schema.*(?:too\s*(?:large|complex)|exceed)/i
].freeze

def strict_grammar_error?(err)
  return false unless err.is_a?(RequestError)
  return false unless err.status_code == 400
  msg = err.message.to_s
  STRICT_GRAMMAR_PATTERNS.any? { |re| msg.match?(re) }
end
```

Place `STRICT_GRAMMAR_PATTERNS` as a module-level constant (visibility
private to `Dispatch::Adapter::MiniMax` is fine; it does not need to be
exposed externally).

### 3. Confirm the retry harness still uses the predicate

Find `chat_streaming_with_strict_fallback` and
`chat_non_streaming_with_strict_fallback` (or whatever the harness
methods are called). Both should call `strict_grammar_error?(error)`
inside their `rescue RequestError => e` block. If they reference some
older predicate name, update them to call the new one.

DO NOT change the rest of the harness logic. The single-shot retry, the
`@strict_disabled = true` latch, and the `disable_strict_tools: true`
forwarding to `RequestBuilder.build` all stay.

## Acceptance criteria

- The matcher returns `true` for a `RequestError` with status `400` and
  message `"compiled grammar too large for tool 'foo'"`.
- The matcher returns `true` for a `RequestError` with status `400` and
  message `"Tool schema is too complex"`.
- The matcher returns `true` for a `RequestError` with status `400` and
  message `"grammar exceeds maximum size"`.
- The matcher returns `false` for a `RequestError` with status `400` and
  message `"missing required field: messages"`.
- The matcher returns `false` for a `RequestError` with status `429`,
  even if the message contains `"grammar"` (status guard).
- The matcher returns `false` for a non-`RequestError` exception.
- `bundle exec rubocop --autocorrect-all` exits 0.

## Verification

Run `run_tests` with `project_path=reference/dispatch-adapter-minimax`.
Rubocop must be clean. `strict_fallback_spec.rb` failures referring to
the broader matcher (e.g. tests asserting it does NOT fire on
"grammar exceeds maximum size") are addressed in phase 16. Other
failures must be investigated.

Test coverage for the new regex variants is added in phase 16. Do NOT
add specs here.
