diff options
| author | Adam Malczewski <[email protected]> | 2026-04-30 20:24:33 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-04-30 20:24:33 +0900 |
| commit | 262aa7395c50b449ce0a897f28b1e33c319f5dc7 (patch) | |
| tree | 2ccc7c7f6402e76aea6b8788046215e82650fdfc /.rules/plan/12-25-update-fixtures.md | |
| parent | 1e7a273bda744f93f230d21df895b54d2a81ce15 (diff) | |
| download | dispatch-adapter-minimax-main.tar.gz dispatch-adapter-minimax-main.zip | |
Diffstat (limited to '.rules/plan/12-25-update-fixtures.md')
| -rw-r--r-- | .rules/plan/12-25-update-fixtures.md | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/.rules/plan/12-25-update-fixtures.md b/.rules/plan/12-25-update-fixtures.md new file mode 100644 index 0000000..d39d24b --- /dev/null +++ b/.rules/plan/12-25-update-fixtures.md @@ -0,0 +1,263 @@ +# Phase 12 — Update fixtures + +**Estimated time:** ~25 minutes +**Touches:** every file under `spec/fixtures/sse/` and +`spec/fixtures/responses/`. + +## Goal + +Replace the Anthropic-shaped fixtures with MiniMax-shaped fixtures that +the rest of the spec suite (phases 13–16) will rely on. + +The MiniMax `/anthropic` endpoint mirrors Anthropic's wire format, so +the fixture STRUCTURE is unchanged — same SSE event names, same JSON +keys, same content blocks. The data INSIDE the fixtures changes: + +- `model` field becomes `MiniMax-M2.7` (or similar MiniMax id). +- Token counts and message ids can be plausible placeholders. +- Tool-use blocks keep the Anthropic shape (`{"type":"tool_use","id":"...","name":"...","input":{...}}`). +- The previously-deleted OAuth fixtures (`oauth-profile.json`, + `oauth-usage-full.json`, `oauth-usage-partial.json`) are GONE per + phase 02; do not recreate them. + +## Steps + +### 1. Inventory the existing fixtures + +The fixtures that must remain (renamed/rewritten): + +```text +spec/fixtures/sse/text-only.sse +spec/fixtures/sse/thinking-then-text.sse +spec/fixtures/sse/tool-use.sse +spec/fixtures/sse/truncated-before-message-start.sse +spec/fixtures/sse/truncated-mid-text.sse +spec/fixtures/responses/messages-text.json +spec/fixtures/responses/messages-tool-use.json +spec/fixtures/responses/messages-with-thinking.json +``` + +Already deleted in phase 02: + +```text +spec/fixtures/responses/oauth-profile.json +spec/fixtures/responses/oauth-usage-full.json +spec/fixtures/responses/oauth-usage-partial.json +``` + +### 2. Rewrite `spec/fixtures/sse/text-only.sse` + +```text +event: message_start +data: {"type":"message_start","message":{"id":"msg_minimax_text01","type":"message","role":"assistant","content":[],"model":"MiniMax-M2.7","stop_reason":null,"usage":{"input_tokens":15,"output_tokens":0}}} + +event: content_block_start +data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}} + +event: ping +data: {} + +event: content_block_delta +data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello, "}} + +event: content_block_delta +data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"world!"}} + +event: content_block_stop +data: {"type":"content_block_stop","index":0} + +event: message_delta +data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":8}} + +event: message_stop +data: {"type":"message_stop"} + +``` + +(Keep the trailing blank line.) + +### 3. Rewrite `spec/fixtures/sse/thinking-then-text.sse` + +```text +event: message_start +data: {"type":"message_start","message":{"id":"msg_minimax_thnk01","type":"message","role":"assistant","content":[],"model":"MiniMax-M2.7","stop_reason":null,"usage":{"input_tokens":42,"output_tokens":0}}} + +event: content_block_start +data: {"type":"content_block_start","index":0,"content_block":{"type":"thinking","thinking":"","signature":""}} + +event: content_block_delta +data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"Considering the question..."}} + +event: content_block_delta +data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" the answer is two."}} + +event: content_block_stop +data: {"type":"content_block_stop","index":0} + +event: content_block_start +data: {"type":"content_block_start","index":1,"content_block":{"type":"text","text":""}} + +event: content_block_delta +data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"The answer is 2."}} + +event: content_block_stop +data: {"type":"content_block_stop","index":1} + +event: message_delta +data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":24}} + +event: message_stop +data: {"type":"message_stop"} + +``` + +NOTE: MiniMax docs do not document `signature` on thinking blocks. The +parser must accept thinking blocks WITHOUT a signature too. Leaving +`"signature":""` here exercises the empty-string branch; if the +existing parser treats empty-string as "no signature", that's fine. + +### 4. Rewrite `spec/fixtures/sse/tool-use.sse` + +```text +event: message_start +data: {"type":"message_start","message":{"id":"msg_minimax_tool01","type":"message","role":"assistant","content":[],"model":"MiniMax-M2.7","stop_reason":null,"usage":{"input_tokens":50,"output_tokens":0}}} + +event: content_block_start +data: {"type":"content_block_start","index":0,"content_block":{"type":"tool_use","id":"toolu_minimax01","name":"get_weather","input":{}}} + +event: content_block_delta +data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"{\"city\":"}} + +event: content_block_delta +data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"\"Boston\"}"}} + +event: content_block_stop +data: {"type":"content_block_stop","index":0} + +event: message_delta +data: {"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"output_tokens":18}} + +event: message_stop +data: {"type":"message_stop"} + +``` + +### 5. Rewrite `spec/fixtures/sse/truncated-before-message-start.sse` + +```text +event: ping +data: {} + +``` + +(Two lines, ending in a blank line. The point of this fixture is that +the stream ends before any `message_start` arrives — the streaming +retry harness should treat this as a transient first-event failure.) + +### 6. Rewrite `spec/fixtures/sse/truncated-mid-text.sse` + +```text +event: message_start +data: {"type":"message_start","message":{"id":"msg_minimax_trunc01","type":"message","role":"assistant","content":[],"model":"MiniMax-M2.7","stop_reason":null,"usage":{"input_tokens":15,"output_tokens":0}}} + +event: content_block_start +data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}} + +event: content_block_delta +data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello" +``` + +(Deliberately ends mid-frame, no terminating blank line. The streaming +retry harness should NOT retry once consumer-visible text has been +emitted.) + +### 7. Rewrite `spec/fixtures/responses/messages-text.json` + +```json +{ + "id": "msg_minimax_resp_text01", + "type": "message", + "role": "assistant", + "model": "MiniMax-M2.7", + "content": [ + { "type": "text", "text": "Hello, world!" } + ], + "stop_reason": "end_turn", + "stop_sequence": null, + "usage": { + "input_tokens": 15, + "output_tokens": 8 + } +} +``` + +### 8. Rewrite `spec/fixtures/responses/messages-tool-use.json` + +```json +{ + "id": "msg_minimax_resp_tool01", + "type": "message", + "role": "assistant", + "model": "MiniMax-M2.7", + "content": [ + { + "type": "tool_use", + "id": "toolu_minimax_resp01", + "name": "get_weather", + "input": { "city": "Boston" } + } + ], + "stop_reason": "tool_use", + "stop_sequence": null, + "usage": { + "input_tokens": 50, + "output_tokens": 18 + } +} +``` + +### 9. Rewrite `spec/fixtures/responses/messages-with-thinking.json` + +```json +{ + "id": "msg_minimax_resp_thnk01", + "type": "message", + "role": "assistant", + "model": "MiniMax-M2.7", + "content": [ + { + "type": "thinking", + "thinking": "Considering the question... the answer is two.", + "signature": "" + }, + { "type": "text", "text": "The answer is 2." } + ], + "stop_reason": "end_turn", + "stop_sequence": null, + "usage": { + "input_tokens": 42, + "output_tokens": 24 + } +} +``` + +## Acceptance criteria + +- All five SSE fixtures exist with the new MiniMax-flavoured content. +- All three response JSON fixtures exist with the new MiniMax-flavoured + content. +- `grep -rn 'claude-sonnet\|claude-3-5\|claude-3.5\|anthropic' spec/fixtures/` + returns ZERO matches. +- `bundle exec rubocop --autocorrect-all` exits 0 (no Ruby files + changed, but invoked via `run_tests`). + +## Verification + +Run `run_tests` with `project_path=reference/dispatch-adapter-minimax`. +Rubocop must be clean. RSpec failures pointing at the fixtures +(expected text strings, model ids, token counts) are routine and will +be reconciled when the corresponding spec is retargeted in phase +13–16. Any failure NOT of that shape must be investigated. + +DO NOT update spec assertions to match the fixtures here — that is +deferred to the retarget phases. |
