1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
|
# Phase 13 — Retarget headers and request-builder specs
**Estimated time:** ~25 minutes
**Touches:**
`spec/dispatch/adapter/minimax/headers_spec.rb`,
`spec/dispatch/adapter/minimax/request_builder_spec.rb`.
## Goal
Update the two specs that exercise the most heavily-modified code:
the simplified `Headers.build` (phase 04) and the MiniMax-specific
constraints in `RequestBuilder.build` (phases 08, 09, 10).
## Pre-reading
Before editing, read these files in full so you know the current
shapes:
1. `lib/dispatch/adapter/minimax/headers.rb`
2. `lib/dispatch/adapter/minimax/request_builder.rb`
3. `spec/dispatch/adapter/minimax/headers_spec.rb`
4. `spec/dispatch/adapter/minimax/request_builder_spec.rb`
## Steps for headers_spec.rb
### 1. Delete every example that asserted on removed behavior
DELETE examples covering:
- `claude_code_only` mode
- `interleaved_thinking` flag handling
- `extra_betas` merging
- `anthropic-version` header presence
- `x-stainless-*` header presence
- `User-Agent: claude-cli/...` header
- OAuth token detection (`sk-ant-oat` prefix)
- The `is_oauth:` keyword
- `anthropic-beta` header construction
Removing these examples is NOT "weakening tests" — they target
deleted code. The behavior they covered no longer exists.
### 2. Replace with a focused MiniMax-only suite
The new spec should cover ONLY the new contract:
```ruby
# frozen_string_literal: true
require "spec_helper"
RSpec.describe Dispatch::Adapter::MiniMax::Headers do
describe ".build" do
it "always sets Authorization to Bearer <api_key>" do
headers = described_class.build(api_key: "k_abc")
expect(headers["Authorization"]).to eq("Bearer k_abc")
end
it "always sets Content-Type to application/json" do
headers = described_class.build(api_key: "k_abc")
expect(headers["Content-Type"]).to eq("application/json")
end
it "sets Accept to application/json when stream is false" do
headers = described_class.build(api_key: "k_abc", stream: false)
expect(headers["Accept"]).to eq("application/json")
end
it "sets Accept to text/event-stream when stream is true" do
headers = described_class.build(api_key: "k_abc", stream: true)
expect(headers["Accept"]).to eq("text/event-stream")
end
it "lets caller extras pass through" do
headers = described_class.build(api_key: "k", extra: { "X-Trace-Id" => "abc" })
expect(headers["X-Trace-Id"]).to eq("abc")
end
it "never lets caller extras override Authorization" do
headers = described_class.build(api_key: "k", extra: { "Authorization" => "Bearer evil" })
expect(headers["Authorization"]).to eq("Bearer k")
end
it "does NOT include anthropic-version, x-stainless, or User-Agent headers" do
headers = described_class.build(api_key: "k")
expect(headers).not_to have_key("anthropic-version")
expect(headers).not_to have_key("anthropic-beta")
expect(headers.keys.grep(/x-stainless/i)).to eq([])
expect(headers).not_to have_key("User-Agent")
end
end
end
```
## Steps for request_builder_spec.rb
### 1. Delete every example covering removed concerns
DELETE examples covering:
- `is_oauth:` parameter behavior (keyword removed in phase 02).
- `proxy_` prefixing of tool names (cloaking deleted in phase 02).
- `metadata: { user_id: ... }` cloaking-derived defaults
(still emit a metadata block when caller supplies one, but no auto-
generated user_id).
- Billing-payload synthetic system block.
- The `claude-3-5-haiku` skip-billing-block special case.
### 2. Update remaining examples to MiniMax shape
For each surviving example:
- Replace `"claude-sonnet-4-5-20250929"` (or whatever the old default
was) with `"MiniMax-M2.7"` in `model` fields and assertions.
- Remove `is_oauth:` from any `RequestBuilder.build` call.
- Update `system` assertion expectations: with cloaking gone, the
system block is exactly what the caller passed (string → wrapped in
one text block; array → passed through; nil → omitted).
### 3. Add new examples for MiniMax constraints
Append new examples that exercise the work from phases 08, 09, 10:
```ruby
context "temperature validation" do
it "raises ArgumentError when temperature is 0.0" do
expect {
described_class.build(model_id: "MiniMax-M2.7", messages: [], system: nil,
tools: [], base_url: "https://api.minimax.io/anthropic",
temperature: 0.0)
}.to raise_error(ArgumentError, /temperature/)
end
it "raises ArgumentError when temperature exceeds 1.0" do
expect {
described_class.build(model_id: "MiniMax-M2.7", messages: [], system: nil,
tools: [], base_url: "https://api.minimax.io/anthropic",
temperature: 1.01)
}.to raise_error(ArgumentError, /temperature/)
end
it "raises ArgumentError when temperature is negative" do
expect {
described_class.build(model_id: "MiniMax-M2.7", messages: [], system: nil,
tools: [], base_url: "https://api.minimax.io/anthropic",
temperature: -0.1)
}.to raise_error(ArgumentError, /temperature/)
end
it "accepts temperature 1.0" do
body = described_class.build(model_id: "MiniMax-M2.7", messages: [],
system: nil, tools: [],
base_url: "https://api.minimax.io/anthropic",
temperature: 1.0)
expect(body[:temperature]).to eq(1.0)
end
it "omits temperature when nil" do
body = described_class.build(model_id: "MiniMax-M2.7", messages: [],
system: nil, tools: [],
base_url: "https://api.minimax.io/anthropic",
temperature: nil)
expect(body).not_to have_key(:temperature)
end
end
context "ignored parameters" do
it "strips top_k from the wire body even if forced via extras" do
body = described_class.build(
model_id: "MiniMax-M2.7", messages: [], system: nil, tools: [],
base_url: "https://api.minimax.io/anthropic"
)
body[:top_k] = 5 # simulate accidental injection
described_class.send(:strip_ignored!, body)
expect(body).not_to have_key(:top_k)
end
# Mirror examples for stop_sequences, service_tier, mcp_servers,
# context_management, container.
end
context "image / document content rejection" do
it "raises ArgumentError when an ImageBlock is present" do
skip "interface gem must define ImageBlock" unless defined?(Dispatch::Adapter::ImageBlock)
msg = Dispatch::Adapter::Message.new(
role: "user",
content: [Dispatch::Adapter::ImageBlock.new(source: { type: "base64", media_type: "image/png", data: "" })]
)
expect {
described_class.build(
model_id: "MiniMax-M2.7", messages: [msg], system: nil, tools: [],
base_url: "https://api.minimax.io/anthropic"
)
}.to raise_error(ArgumentError, /MiniMax does not support image/)
end
end
```
NOTE on `skip`: the rule says "no skipped or pending examples after
phase 17". If the interface gem actually exposes `ImageBlock` /
`DocumentBlock`, REMOVE the `skip` and replace with concrete
construction. Verify by reading
`reference/dispatch-adapter-minimax/Gemfile.lock` →
`dispatch-adapter-interface` source location, then grep that gem for
`class ImageBlock` / `class DocumentBlock`. If they exist, write the
spec without `skip`. If they don't exist, REMOVE the example entirely
(do not leave a `skip`). Document briefly in a comment why no example
exists for image rejection.
## Acceptance criteria
- `headers_spec.rb` and `request_builder_spec.rb` both pass cleanly
(no `.skip`, no `.pending`).
- `grep -n 'is_oauth\|sk-ant-oat\|claude_code_only\|anthropic-beta\|x-stainless\|claude-cli\|proxy_\|interleaved_thinking\|extra_betas' spec/dispatch/adapter/minimax/headers_spec.rb spec/dispatch/adapter/minimax/request_builder_spec.rb`
returns ZERO matches.
- `bundle exec rubocop --autocorrect-all` exits 0.
## Verification
Run `run_tests` with `project_path=reference/dispatch-adapter-minimax`.
Both rubocop and the two retargeted spec files must pass cleanly. Other
spec failures are acceptable here (handled in phases 14–16).
|