Claude vs ChatGPT Editing Test: 12 Steps, 75 Min [2026] A 12-step, 75-minute editing test built on a small Python harness called `editlab` measures how much Claude and ChatGPT models change a writer's prose when asked only to fix typos, rather than judging new writing on taste. The comparison pairs Anthropic's Claude Haiku 5.5, listed at $0.10 per million input tokens and $0.50 per million output tokens, against OpenAI's GPT-6 Luna at the same $0.10/$0.50 rate card, and Claude Sonnet 5.5 against GPT-6 Sol at $2.00 input and $10.00 output per million tokens. The test accounts for OpenAI's October 30 update to GPT-6 in ChatGPT, which cut overly flattering language and made answers more concise, meaning app-based results collected before that date describe a different assistant. Anthropic’s cheapest current writer, Claude Haiku 5.5, lists at $0.10 per million input tokens and $0.50 per million output tokens for prompts up to 100,000 tokens, according to its platform documentation https://platform.claude.com/docs/en/models/haiku-5-5/overview . OpenAI shows the same $0.10 and $0.50 rate card price for GPT-6 Luna, the model behind ChatGPT’s Free and Go plans. Two models at identical prices can still behave very differently the moment you hand them someone else’s prose. On the OpenAI side, GPT-6 is mid-rollout. Plus, Pro, Business and Enterprise accounts run GPT-6 Sol, while Free and Go run GPT-6 Luna, OpenAI’s pricing page https://chatgpt.com/pricing/ shows. A November 2 roundup https://csuite.so/blog/why-your-ai-doesnt-know-last-week describes the rollout as still in progress, so two people on different plans can get different models under one “ChatGPT” label. That detail matters for any Claude vs ChatGPT test, and it drives most of the design choices in the harness. Most comparisons ask each model to write something new and then argue about taste. A blind drafting test https://shattered.io/claude-vs-chatgpt-for-writing-blind-test-12-steps-2026/ handles that well. Editing is a different job. When a writer hands over a draft and says “fix the typos,” the best answer changes almost nothing else. Some models quietly swap words, soften slang, reformat numbers or add a flourish. A small Python harness called editlab can measure that restraint with plain arithmetic instead of a vibe check. Don't miss new tech stories on Google Add Shattered once in the Google app and our stories show up in your news suggestions. Add now https://www.google.com/preferences/source?hl=en&q=https%3A%2F%2Fshattered.io%2F Claude vs ChatGPT for Editing: The Lineup and Why This Test The model names move fast, so the first job is to pin down what exists today. Anthropic announced Claude Opus 5.5 on September 22, 2026, Claude Sonnet 5.5 on September 28, and Claude Haiku 5.5 on October 7. Anthropic says Sonnet 5.5 runs more than 30% faster than Sonnet 5 and costs up to 30% less for most work. Haiku 5.5 is the first Haiku-class model with an adjustable effort setting, which matters because effort changes how much a model deliberates before it touches your text. OpenAI’s lineup in ChatGPT centers on GPT-6, with Sol on paid tiers and Luna on Free and Go. OpenAI’s release notes say that on October 30 it updated GPT-6 in ChatGPT to give more concise answers and cut overly flattering language. That is a behavior change that lands squarely on editing. Any app-based result collected before that date describes a different assistant. | Tier | Claude option | ChatGPT option | List price per 1M tokens input / output | |---|---|---|---| | Small and cheap | Claude Haiku 5.5 Oct 7, 2026 | GPT-6 Luna | $0.10 / $0.50 for both | | Mid-range | Claude Sonnet 5.5 Sep 28, 2026 | GPT-6 Sol | $2.00 / $10.00 for both | | Top tier | Claude Opus 5.5 Sep 22, 2026 | GPT-6 Pro | Opus: see Anthropic’s pricing page. GPT-6 Pro: $10 / $50 | | Consumer entry | Free, Pro, Max, Ultra plans | Free $0, Go $6, Plus $20 per month | Not applicable | The pairing logic falls out of that table. Haiku 5.5 against GPT-6 Luna is a fair fight on price, and so is Sonnet 5.5 against GPT-6 Sol. Comparing Opus to a cheap tier would tell you about budgets, not about editing behavior. The harness therefore takes model aliases from a config file, and you pick the pair that matches what you actually pay for. Anthropic and OpenAI both publish mid-tier prices at $2 input and $10 output, which makes the cost column of your final report easy to read. Why build an editing test at all? Because editing failures are quiet and expensive. A model that improves a contract email by rewording the indemnity clause creates legal risk. A model that turns an exact dollar figure into a rounded shorthand changes a figure without telling you. A model that cleans up dialect in fiction erases the author. The same skeleton can later feed a multi-stage writing pipeline https://shattered.io/chatgpt-vs-claude-writing-pipeline-terra-opus-5-5-12-steps-2026/ , but the editing case is the sharpest place to see restraint. Four numbers carry most of the signal. The fix rate counts how many seeded errors each model repairs. The over-edit rate counts how many words change beyond those repairs. The protected-span rate checks that names, figures and code survive untouched. The voice rate checks that the author’s quirks remain. A weighted fidelity score rolls them into one number from 0 to 100. Prerequisites and Versions Everything below ran on Python 3.12.3 on Linux. The offline path uses only the standard library, so the dry run in step 11 works even if you skip the pip install in step 1 and never spend a cent. The vendor SDKs load lazily, only when a live provider is built. | Component | Version or requirement | Why it matters | |---|---|---| | Python | 3.11 or newer tested on 3.12.3 | difflib , statistics and dataclasses ship with it | | anthropic SDK | Latest release from PyPI | Messages API for Claude models | | openai SDK | Latest release from PyPI | Chat Completions for GPT models | | Test runner | Built-in unittest | No pytest install needed | | API keys | One Anthropic key, one OpenAI key | Live run in step 12 only | | Shell | bash, zsh or PowerShell | Windows users should set PYTHONUTF8=1 | | Budget | Roughly $0.01 to $0.30 per model | Depends on the tier you pick | | Time | About 75 minutes | Most of it is reading the report | Two things to settle before you start. First, decide which pair you are testing and write down today’s date, because model behavior shifts under the same name. Second, decide whether you are testing the API or the chat app. They are not the same product. API billing is separate from ChatGPT subscriptions, and the app adds memory, custom instructions and interface features that an API call never sees. This harness tests the API, which is the only place you can control inputs and log every token. Steps 1 and 2: Project Skeleton and Pinned Models Step 1 creates the folder, a virtual environment and the package layout. Step 2 pins which models the harness will call. mkdir editlab && cd editlab python3 -m venv .venv source .venv/bin/activate Windows: .venv\Scripts\Activate.ps1 mkdir -p editlab data tests runs touch editlab/ init .py pip install anthropic openai Create requirements.txt so a teammate can reproduce the environment, and .env.example so nobody commits a key by accident. Copy the example to .env and fill it in. Add .env and runs/ to your .gitignore . anthropic openai ANTHROPIC API KEY= OPENAI API KEY= Copy the exact model IDs from each vendor's models page on the day you run the test. CLAUDE MODEL=claude-haiku-5-5 OPENAI MODEL= The environment file stores model IDs rather than hard-coding them in Python, and that choice is deliberate. Only one ID is filled in above: claude-haiku-5-5 , the identifier Anthropic documents for Haiku 5.5. For every other model, copy the exact ID from the vendor’s models page on the day you run the test. Guessing at IDs from memory is how people end up testing a retired snapshot while labeling the result with a current name. If you want a view on how plan limits and prices differ across the two vendors, the plan and usage-limit comparison https://shattered.io/chatgpt-vs-claude-pricing-usage-limits-pro-500-opus-5-5-2026/ lines up the consumer tiers. The models.json file maps friendly aliases to providers and prices. The usd in and usd out fields hold dollars per million tokens, and the defaults below use the $0.10 and $0.50 cheap-tier rate. Change them to $2 and $10 if you test Sonnet 5.5 against GPT-6 Sol. Check Anthropic’s pricing documentation https://docs.anthropic.com/en/docs/about-claude/pricing on the day you run, because prices change. { "models": {"alias": "claude", "provider": "anthropic", "model env": "CLAUDE MODEL", "usd in": 0.10, "usd out": 0.50}, {"alias": "chatgpt", "provider": "openai", "model env": "OPENAI MODEL", "usd in": 0.10, "usd out": 0.50}, {"alias": "fake-light", "provider": "fake", "model": "light"}, {"alias": "fake-heavy", "provider": "fake", "model": "heavy"} } Now config.py , which loads the .env file without any third-party dependency, resolves aliases into concrete model IDs, and refuses to run when an ID is missing. The refusal is a feature. A silent fallback to a default model would corrupt every row of your results. python import json import os from pathlib import Path ROOT = Path file .resolve .parent.parent def load env path=ROOT / ".env" : if not Path path .exists : return for line in Path path .read text .splitlines : line = line.strip if not line or line.startswith " " or "=" not in line: continue key, value = line.split "=", 1 os.environ.setdefault key.strip , value.strip def load models aliases : spec = json.loads ROOT / "models.json" .read text "models" by alias = {m "alias" : m for m in spec} chosen = for alias in aliases: if alias not in by alias: raise SystemExit f"Unknown alias {alias r}. Known: {sorted by alias }" entry = dict by alias alias if "model env" in entry: model id = os.environ.get entry "model env" , "" .strip if not model id: raise SystemExit f"Set {entry 'model env' } in .env before running {alias}." entry "model" = model id chosen.append entry return chosen def load drafts : return json.loads ROOT / "data" / "drafts.json" .read text Step 3: Build Fixture Drafts With Seeded Errors An editing test needs inputs where the correct answer is known. The fixtures are six short drafts in different registers: a casual blog post, a formal email, a technical runbook with inline code, dialect fiction, a press release dense with figures, and a lowercase chat message. Each draft carries three kinds of metadata. - Seeded errors are typos and doubled words with a known fix, such as “untill” to “until” or “the the” to “the”. Applying them to the draft produces the gold text. - Protected spans are strings that must survive verbatim: dollar amounts, dates, names, version numbers and code in backticks. - Voice markers are phrases that make the author sound like themselves, such as “Honestly,” or “i’m not gonna”. A model that polishes them away has overreached. Every name, company and figure in these fixtures is invented, so you can publish results without leaking anything real. Keep it that way. Do not paste real customer emails into a test that sends text to two vendors, and do not reuse drafts you plan to feed to a production assistant with memory enabled. { "id": "blog-casual", "genre": "casual blog post", "text": "Honestly, we shipped the new dashboard on Tuesday and nobody noticed untill Thursday. The team had been working on it for 14 weeks, and the budget came in at $48,200, which is way under what Priya estimated. I think thats the real story here. Teh load time dropped from 3.4 seconds to 1.1 seconds, and support tickets fell by 22%. We still have two bugs to squash, but honestly, I'd ship it again tomorrow.", "errors": {"wrong": "untill", "right": "until"}, {"wrong": "thats", "right": "that's"}, {"wrong": "Teh", "right": "The"} , "protected": "14 weeks", "$48,200", "Priya", "3.4 seconds", "1.1 seconds", "22%" , "voice": "Honestly,", "honestly,", "I'd ship it again tomorrow" }, { "id": "email-formal", "genre": "business email", "text": "Hi Marcus, I wanted to follow up on the contract we discussed on March 12. The vendor has agreed to a 36-month term at $9,400 per month, but they want payment recieved within 15 days of invoice, wich is shorter than our usual 30 days. Please review section 4.2 and let me know if legal sees any issues with the the indemnity clause. I'll hold the signature page until Friday. Best, Dana", "errors": {"wrong": "recieved", "right": "received"}, {"wrong": "wich", "right": "which"}, {"wrong": "the the indemnity", "right": "the indemnity"} , "protected": "March 12", "36-month", "$9,400", "15 days", "30 days", "section 4.2", "Marcus", "Dana" , "voice": "I'll hold the signature page" }, { "id": "tech-doc", "genre": "technical runbook", "text": "To rotate the key, run kubectl rollout restart deployment/api-gateway -n prod and wait for the pods to come back. The the rollout usually takes about 90 seconds. If the readiness probe fails, check the logs with kubectl logs -l app=api-gateway --tail=50 before you retry. Dont skip this step, because a half-rotated key will lock out every client for upto 5 minutes.", "errors": {"wrong": "The the rollout", "right": "The rollout"}, {"wrong": "Dont", "right": "Don't"}, {"wrong": "upto", "right": "up to"} , "protected": " kubectl rollout restart deployment/api-gateway -n prod ", " kubectl logs -l app=api-gateway --tail=50 ", "90 seconds", "5 minutes" , "voice": "half-rotated" }, { "id": "fiction-dialect", "genre": "dialect fiction", "text": "Ma said the river was risin', and Ma was never wrong about water. We carried the quilts up to the loft while Pa cussed at the mule. \"Ain't no sense in waitin',\" he said, but he was already hauling the seed bags. By midnite the yard was a lake and the chickens roosted on the porch rale. I countd seven of them, plus the one-eyed rooster Pa swore he'd eat by Sunday.", "errors": {"wrong": "midnite", "right": "midnight"}, {"wrong": "rale", "right": "rail"}, {"wrong": "countd", "right": "counted"} , "protected": "seven", "Ma", "Pa", "Sunday", "one-eyed rooster" , "voice": "risin'", "Ain't no sense in waitin'", "cussed" }, { "id": "press-release", "genre": "press release", "text": "Northwind Labs today announced a $12.5 million Series A led by Cobalt Ventures, bringing total funding to $18 million. The round will fund hiring of 40 engineers across Austin and Lisbon by Q2 2027. CEO Imani Okafor said the compnay has grown revenue 3x year over year, and plans to open its API to outside developers in Janaury. The announcment follows a pilot with 120 customers.", "errors": {"wrong": "compnay", "right": "company"}, {"wrong": "Janaury", "right": "January"}, {"wrong": "announcment", "right": "announcement"} , "protected": "$12.5 million", "Cobalt Ventures", "$18 million", "40 engineers", "Austin", "Lisbon", "Q2 2027", "Imani Okafor", "3x", "120 customers" , "voice": }, { "id": "slack-lowercase", "genre": "lowercase chat message", "text": "ok so the migration finished at 3:40am and the checksum diff came back clean for 2,184 of 2,190 tables. six tables failed becuase of the legacy enum thing we already knew about. i'm not gonna touch them till standup. @renee can you confrim the replica lag was under 200ms the whole time? if so we can drop the old cluster on friday.", "errors": {"wrong": "becuase", "right": "because"}, {"wrong": "confrim", "right": "confirm"} , "protected": "3:40am", "2,184 of 2,190", "@renee", "200ms", "friday" , "voice": "ok so", "i'm not gonna", "till standup" } Six drafts is a starting point, not a verdict. It is enough to separate a model that edits with a light hand from one that rewrites, as the dry run in step 11 shows. It is not enough to rank two careful editors, and the advanced tips explain how to size the sample once you care about small gaps. Aim for at least 20 drafts, drawn from your own writing, before you act on a result. One design note on the errors. Each wrong string appears exactly once in its draft, so a plain string replacement builds the gold text with no ambiguity. If you add your own drafts, check that property, or the gold text will drift and your over-edit numbers will carry a hidden bias. Steps 4 and 5: Prompts and Provider Adapters Step 4 defines three prompts that mirror how real people ask for edits. The strict prompt spells out the rules: fix only spelling, doubled words and clear grammar, keep voice, leave numbers and code alone, return the text with no commentary. The light prompt is the lazy version, “proofread this.” The polish prompt invites change on purpose. Running all three tells you whether a model’s restraint comes from its habits or from your instructions. STRICT = "You are a copy editor. Fix only spelling, typos, doubled words, and clear grammar " "errors. Do not rephrase, reorder, shorten, or add anything. Keep the author's voice, " "slang, dialect, and capitalization. Leave numbers, names, code, and quoted text " "exactly as written. Return only the corrected text with no commentary." LIGHT = "Proofread this text and return the corrected version only." POLISH = "Improve this text so it reads better. Return the improved text only." PROMPTS = {"strict": STRICT, "light": LIGHT, "polish": POLISH} def user message draft text : return f"