diff options
Diffstat (limited to '.rules/plan/14-25-retarget-response-builder-and-streaming-internals-specs.md')
| -rw-r--r-- | .rules/plan/14-25-retarget-response-builder-and-streaming-internals-specs.md | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/.rules/plan/14-25-retarget-response-builder-and-streaming-internals-specs.md b/.rules/plan/14-25-retarget-response-builder-and-streaming-internals-specs.md new file mode 100644 index 0000000..32c5176 --- /dev/null +++ b/.rules/plan/14-25-retarget-response-builder-and-streaming-internals-specs.md @@ -0,0 +1,161 @@ +# Phase 14 — Retarget response-builder and streaming-internals specs + +**Estimated time:** ~25 minutes +**Touches:** +`spec/dispatch/adapter/minimax/response_builder_spec.rb`, +`spec/dispatch/adapter/minimax/sse_parser_spec.rb`, +`spec/dispatch/adapter/minimax/stream_collector_spec.rb`. + +## Goal + +Update the three specs that consume the new fixtures created in phase +12. The structural change is small: with `is_oauth` and cloaking gone +(phase 02), there is no `proxy_` prefix to strip, and the response / +stream pipelines are pure Anthropic-compatible parsers fed by MiniMax- +shaped data. + +## Pre-reading + +1. `spec/fixtures/sse/*.sse` (already updated in phase 12) +2. `spec/fixtures/responses/*.json` (already updated in phase 12) +3. `lib/dispatch/adapter/minimax/response_builder.rb` +4. `lib/dispatch/adapter/minimax/sse_parser.rb` +5. `lib/dispatch/adapter/minimax/stream_collector.rb` + +## Steps for response_builder_spec.rb + +### 1. Drop the `is_oauth` parameter from every call + +`ResponseBuilder.build(json, model_info: ..., is_oauth: ...)` becomes +`ResponseBuilder.build(json, model_info: ...)`. Phase 02 removed the +keyword from the lib code; remove it from all spec calls here. + +### 2. Update fixture references and assertions + +The fixtures are now MiniMax-flavoured: + +- `model: "MiniMax-M2.7"` instead of a Claude id. +- Token counts changed (input 15/50/42, output 8/18/24). +- `id` strings begin with `msg_minimax_*` and `toolu_minimax_*`. +- Tool name in tool-use fixtures is `"get_weather"` with input + `{"city":"Boston"}`. + +Update every assertion that compared against old values. + +### 3. Drop the cloaking strip-prefix examples + +Any example asserting that `proxy_get_weather` arrives in the response +and is stripped to `get_weather` before being returned should be +DELETED. There is no proxy prefix to strip anymore — MiniMax sends +plain tool names. + +### 4. Cost assertions + +Examples that asserted `usage.cost.total_cost > 0.0` (or any non-zero +sub-cost) must be updated to expect `0.0` because phase 06 zeroed the +pricing table. Token counts are still meaningful — only the +*per-token rate* is zero. + +### 5. Remove cache_creation/cache_read examples that depended on +non-zero pricing if any. + +If the old `messages-text.json` exposed cache token counts, the +fixture in phase 12 may not include them. Add them back ONLY IF the +spec needs to exercise that code path (i.e. a `usage_hash` with +`cache_creation_input_tokens` / `cache_read_input_tokens`). If you do, +edit `spec/fixtures/responses/messages-text.json` to add those keys to +`usage` — phase 12's fixture omits them but adding them is fine. + +## Steps for sse_parser_spec.rb + +### 1. Update model id references + +Replace `"claude-sonnet-4-5-20250929"` (or whatever Claude model id was +used) with `"MiniMax-M2.7"` in any in-spec hand-built event payloads. + +### 2. Re-load fixtures + +Specs that read SSE fixtures by path (`File.read("spec/fixtures/sse/text-only.sse")`) +will pick up the new content automatically. Update the assertions to +match the new event count and content: + +- `text-only.sse` → 8 frames (text-only fixture: message_start, + content_block_start, ping, content_block_delta×2, content_block_stop, + message_delta, message_stop). Verify by reading the fixture. +- `tool-use.sse` → 7 frames. +- `thinking-then-text.sse` → 11 frames. + +Update text/tool/thinking string assertions to match the new fixture +content (`"Hello, world!"` → `"Hello, "` + `"world!"`, +`"get_weather"` with city=Boston, etc.). + +### 3. Truncated fixtures + +`truncated-mid-text.sse` ends mid-frame after emitting some text +deltas. The parser is content-agnostic at chunk boundary; the higher- +level `StreamCollector` decides whether to retry. The parser-level +spec should assert that `flush` raises `RequestError` (because there +is dangling non-empty data when the stream ends). + +`truncated-before-message-start.sse` is just a `ping` event followed +by EOF — the parser yields the ping (or silently drops it depending on +implementation) and `flush` is a no-op since there is no dangling data. + +## Steps for stream_collector_spec.rb + +### 1. Drop `is_oauth:` from `StreamCollector.new` calls + +Phase 02 removed the keyword. Remove from spec setup. + +### 2. Update fixture-driven assertions + +For the `text-only.sse` fixture, the collector should now assemble: + +- One `TextBlock` with text `"Hello, world!"` +- `stop_reason: :end_turn` +- `usage.input_tokens: 15` +- `usage.output_tokens: 8` +- `model: "MiniMax-M2.7"` + +For `tool-use.sse`: + +- Zero text blocks. +- One `ToolUseBlock` with id `toolu_minimax01`, name `get_weather`, + arguments `{"city" => "Boston"}`. +- `stop_reason: :tool_use`. +- `usage.input_tokens: 50`, `usage.output_tokens: 18`. + +For `thinking-then-text.sse`: + +- One `ThinkingBlock` with thinking + `"Considering the question... the answer is two."` and signature `""` + (or `nil`, depending on how the existing builder handles empty + signatures — match the actual lib behavior). +- One `TextBlock` with text `"The answer is 2."` +- `stop_reason: :end_turn`. + +### 3. Drop cloaking assertions + +Any assertion that the collector strips a `proxy_` prefix from tool +names should be DELETED — there is no prefix to strip. + +### 4. Cost assertions + +Same as response builder spec: update any cost assertions to expect +`0.0` since pricing is zeroed. + +## Acceptance criteria + +- `response_builder_spec.rb`, `sse_parser_spec.rb`, and + `stream_collector_spec.rb` all pass cleanly. +- No `.skip` or `pending` examples remain in any of the three. +- `grep -n 'is_oauth\|proxy_\|claude-sonnet\|claude-3' spec/dispatch/adapter/minimax/{response_builder_spec,sse_parser_spec,stream_collector_spec}.rb` + returns ZERO matches. +- `bundle exec rubocop --autocorrect-all` exits 0. + +## Verification + +Run `run_tests` with `project_path=reference/dispatch-adapter-minimax`. +Rubocop and these three retargeted specs must pass. Other spec +failures (chat_*, list_models, etc.) are acceptable and fixed in +phases 15–16. |
