Skip to content

devlog/model-bench/one-refactor-two-models-opus-55-and-sonnet-55-1066.md

One Refactor, Two Models: Opus 5.5 and Sonnet 5.5

Opening the Refactor by Dumping Every File into Claude Opus 5.5

The first mistake happens before a single line changes. You open Claude Code, paste the output of a full repository tree into the prompt, attach the four biggest modules, and ask Claude Opus 5.5 to modernize the whole thing at once. The model obliges. It rewrites the boundary layer, renames half the exports, and quietly changes two error contracts you did not mention. Two hours later you are reading a diff you cannot reason about, and the branch is no longer a refactor but a rewrite with no rollback point.

The fix is boring and it works. Split the work into layers and give each layer an explicit entry point. Ask Claude Opus 5.5 for a dependency map of the files you plan to touch, then order the work so leaf modules move first and callers move after. State the invariants that must not change in the prompt itself: function signatures, serialization shapes, error codes, and test names. When the model has to preserve something, say it out loud instead of hoping it infers it from the code.

  • Give each prompt one seam of the system and a short list of files to read before editing anything at all.
  • Ask for a plan and a dependency order before you allow any write operations to begin on the branch.
  • Pin the contracts that must survive the refactor so the model does not redesign them silently.

A repository is a conversation, not a payload. Treat the first prompt as an architecture review and the second prompt as the first edit.

Letting Claude Sonnet 5.5 Touch Callers Before the Core Is Stable

The second mistake is a sequencing error. You decide that Claude Opus 5.5 is expensive and reserve it for the hard core, while Claude Sonnet 5.5 updates the surrounding services, tests, and examples. In principle that is a sensible split. In practice the cheaper model starts rewriting dozens of call sites against an interface that is still moving underneath it, and every core change invalidates a dozen files it already touched.

Reverse the order. Freeze the core first. Have Claude Opus 5.5 finish the inner module, run the tests, and commit when the surface is quiet. Only then hand the fan-out to Claude Sonnet 5.5, which is genuinely fast at mechanical migrations: updating imports, adjusting call sites, rewriting fixtures, and aligning test helpers with the new signatures. Give it the frozen interface as a literal reference so it copies instead of inventing.

  • Freeze and commit the innermost module before any model is allowed to update dependent code.
  • Hand mechanical fan-out work to Claude Sonnet 5.5 once the interface stops changing underneath.
  • Pass the final signature list as text so the fan-out model copies it instead of guessing.

This is where a relay earns its keep. I keep one key and one base URL, https://api.fluxorelay.com, and switch models between passes without rewiring my tools or juggling vendor accounts mid-branch. The same endpoint that serves Claude Opus 5.5 and Claude Sonnet 5.5 also carries GPT, Gemini, DeepSeek, Kimi, GLM, Qwen, Grok and more, so the swap is a parameter, not a migration.

Ignoring Cache Reads and Cache Writes in the Refactor Budget

Refactors are long-running sessions, and long-running sessions are where caching silently becomes the whole bill. You start a session, the relay writes the system prompt and the repo context into a cache, and then you spend two hours asking for revisions. The first call pays cache writes. Every revision after that pays cache reads. If your mental model is a flat per-request price, your estimate is wrong in both directions: early calls look expensive and the long tail looks suspiciously cheap.

The practical response is to price the work the way it is actually billed. Fluxo charges per real token, including cache reads and cache writes, with no monthly fee, so the numbers you see reflect the session you actually ran. Keep one stable system prompt and one stable file set across a burst of edits so the cache keeps hitting, and split genuinely different tasks into new sessions so you are not carrying stale context that costs money and dilutes the prompt.

  • Keep the system prompt and file set stable across revision bursts so cache reads keep hitting.
  • Open a fresh session when the task changes shape instead of carrying irrelevant context forward.
  • Count cache reads and cache writes in your estimate because they are real tokens you pay for.

You can watch the pattern in your dashboard within one refactor: a fat first call, then a row of cheap reads, then a spike the moment you change the context window.

Switching Models Mid-Session Without Carrying the Decisions Forward

The third mistake is losing the reasoning when you change models. You do the hard design pass with Claude Opus 5.5, close the terminal because a meeting starts, and come back to run the mechanical pass with Claude Sonnet 5.5 in a brand new session with no memory of the constraints you agreed on. The new session re-derives a slightly different architecture, and you merge two incompatible design decisions without noticing.

Write the decisions down in the repository instead of in the chat. A short decisions file listing the chosen approach, the rejected alternatives, and the invariants is worth more than any clever prompt. Feed that file into every later session as the first thing the model reads. Then the handoff is boring in the best way, and Claude Sonnet 5.5 executes a plan it did not have to invent.

  • Record decisions and rejected alternatives in a file that every later session reads first.
  • Summarize the constraints at the top of each new prompt so the handoff stays explicit.
  • Verify the invariants with tests before switching models so the next session starts from proof.

Because the setup works with Claude Code, Codex, Gemini CLI and any OpenAI SDK, the same decisions file survives a tool change too, which matters more than it sounds when you move between a laptop and a remote box.

Asking Both Models the Same Question and Keeping Both Answers

Another trap is treating two models as two reviewers and then merging both sets of edits. You ask Claude Opus 5.5 and Claude Sonnet 5.5 to fix the same failing test, both produce working patches, and you keep pieces of each. The result compiles, passes, and quietly contains two strategies for the same problem: one lazy initialization and one eager one, two naming conventions, two ways of handling an empty list.

Make one model the owner of each module and the other the reader. Have Claude Opus 5.5 propose the structural change, then ask Claude Sonnet 5.5 to review that exact diff for correctness and drift rather than to solve the problem again. When you do want a second implementation, keep it on a scratch branch and pick one. Divergence is data, not something to be averaged.

  • Assign a single owning model to each module so the other model only reviews the resulting diff.
  • Keep alternative implementations on separate branches and choose one before merging anything.
  • Ask the reviewing model to flag naming and strategy drift instead of rewriting the solution.

Skipping the Diff Review After a Two-Model Refactor

The final mistake is the one everybody makes under time pressure: trusting the green test run and merging. Two models have edited the same repository through an afternoon, and tests only cover what you thought to test. The dangerous changes are usually small and boring: a default argument that flips behavior, a retry loop that now swallows a cancellation, a logging call that pulls a heavy object into a hot path.

Read the diff by file, not by commit, and read it in dependency order. Ask Claude Sonnet 5.5 for a plain list of behavioral changes it can find in the diff, then verify each claim yourself against the code. Run the test suite twice, once with the old fixtures and once with regenerated ones, and look at the actual output rather than the exit code. Twenty minutes here is the difference between a refactor and an incident.

  • Review the diff file by file in dependency order so callers and callees are checked together.
  • Ask the model to list behavioral changes and then verify each claim against the real code.
  • Compare old and regenerated fixtures so you notice silent output changes before merging.

If you want to run this split yourself, create a Fluxo account and you will get the key and base URL in the dashboard within a minute. If anything here needs a correction or you hit a case this article does not cover, leave a note on the contact page after signing in.

Next in the buffer