Слепое сравнение · один промпт · три агента

Claude Code, Codex и Cursor на одном ТЗ, написанном прозой

Три пустых репозитория, дословно одинаковый промпт, отправленный по одному разу, таймер 15 минут и запрет на любые подсказки. Результаты приняты руками и переоценены двумя независимыми судьями, которые не знали, кто какой код написал.

21 августа 2026 Задача: модуль расчёта корзины, PHP 8.2 Три прогона + три независимые приёмки

01Условия прогона

Всё, что могло дать одному из агентов преимущество, выравнивалось заранее.

Что фиксировалиКак именно
Стартовое состояниеТри пустых каталога bench-claude/, bench-codex/, bench-cursor/, в каждом только пустой git-репозиторий. Ни README, ни конфигов, ни заготовок.
ПромптОдин файл PROMPT.txt, подставлялся всем трём дословно и ровно один раз. Никаких уточнений, дополнений и повторных отправок.
ТаймерЖёсткий timeout -k 15s 900s на процесс. Что не успел — не успел.
ВмешательствоНулевое. Не подсказывали, не чинили, не перезапускали. Ни один агент не задал уточняющего вопроса — все три отработали в один заход.
Изоляция окруженияОтдельные CLAUDE_CONFIG_DIR и CODEX_HOME с одной только авторизацией: без хуков, плагинов, MCP-серверов, пользовательских настроек, памяти и файлов CLAUDE.md/AGENTS.md. У Cursor — свежая установка CLI.
ПорядокПоследовательно, по одному. Никто не делил CPU с соседом во время своих 15 минут.
Приёмкаcomposer install && composer test и прогон CLI выполнены руками, а не со слов агента. Плюс две независимые слепые оценки.

Кто участвовал

АгентМодельТариф
Claude Code CLI 2.1.238opus (Claude Opus 5, 1M)подписка
Codex CLI 0.142.5gpt-5.5, reasoning mediumподписка ChatGPT
Cursor CLI 2026.08.11composer-2.5 (Composer 2.5)собственная модель Cursor

Cursor CLI устанавливался с нуля и авторизовался в рамках этого прогона. Модель выбрана собственная — Composer 2.5, как и просили: не заимствованная у другого вендора.

02Итог

Баллы — среднее трёх независимых оценок по рубрике на 30 пунктов. Все три оценщика выстроили агентов в одном и том же порядке.

1 место
Claude Code
Opus 5 · 891 с
30,0 / 30
все три судьи поставили полный балл
тестов: 129 / 402 проверки доделок до мержа: 0 токенов: 2,24 млн · $3,92
2 место
Cursor
Composer 2.5 · 155 с
29,8 / 30
29,5 · 30 · 30
тестов: 49 / 96 проверок доделок до мержа: 0–1 токенов: 410 тыс.
3 место
Codex
GPT-5.5 · 212 с
28,3 / 30
27,0 · 28,5 · 29,5
тестов: 17 / 58 проверок доделок до мержа: 1–2 токенов: 277 тыс.
Главное, что показал прогон

Функционально все три справились: на шести кейсах из семи суммы совпали копейка в копейку — и между собой, и с эталоном, посчитанным вручную по тексту ТЗ. Разошлись они не в арифметике, а в том, что делают с противоречием, спрятанным в ТЗ, и насколько честно отчитываются о сделанном.

03Время и токены

Все три уложились в таймер. Никто не был остановлен по времени.

МетрикаClaude CodeCodexCursor
Время работы891 с 99 % таймера212 с155 с
Код возврата000
Ходов / сообщений агента33124
Вызовов инструментов321654
Входные токены6434 20823 133
Выходные токены78 50010 22228 473
Чтение из кэша2 065 738232 320358 144
Запись в кэш92 07000
Всего токенов2 236 372276 750409 750
Стоимость прогона$3,92не раскрывается CLIне раскрывается CLI
Токенов на один тест17 33616 2798 362

Строки «ходов» и «вызовов инструментов» между CLI сопоставимы лишь приблизительно: каждый считает их по-своему (Claude — num_turns, Codex — сообщения агента и выполненные команды, Cursor — события tool_call). Токены взяты из финальных usage каждого CLI: у Codex поле input_tokens включает кэшированные, поэтому они разнесены, чтобы не задвоиться.

Claude израсходовал в 8 раз больше токенов, чем Codex, и в 5,5 раза больше времени, чем Cursor. Львиная доля — чтение из кэша: 2,07 млн из 2,24 млн, то есть агент 33 раза перечитывал растущий контекст, дописывая и перепроверяя тесты. Cursor при этом сделал больше всех вызовов инструментов (54) за наименьшее время — он работал мелкими быстрыми шагами.

04Что получилось на выходе

АртефактClaude CodeCodexCursor
Файлов в репозитории441231
Классов в src/27216
Строк src/ + bin/1 690319835
Строк тестов1 367283563
Тест-методов831738
Тестов PHPUnit / проверок129 / 40217 / 5849 / 96
README.md161 стр.56 стр.95 стр.
CHANGELOG.md70 стр.8 стр.16 стр.
NOTES.md140 стр.11 стр.53 стр.

05Ручная приёмка

Всё ниже запускалось руками на оригинальных репозиториях. Отчётам агентов не верили: эталонные суммы посчитаны отдельно по тексту ТЗ до того, как был открыт хоть один файл с кодом.

Тесты и запуск

ПроверкаClaude CodeCodexCursor
composer installчисточисточисто
composer testOK 129 / 402OK 17 / 58OK 49 / 96
Те же тесты под датой 2027-06-15
через faketime, требование «тесты проходят и в 2027»
OK 129 / 402OK 17 / 58OK 49 / 96
Пример из README отрабатываетдадада
float в денежной логикенетнетнет
declare(strict_types=1)28 / 28 файлов3 / 317 / 17
Битый JSON → stderr + код ≠ 0код 1код 1код 1
Переполнение int в ценекод 1, понятный текстPHP Fatal, код 255PHP Fatal, код 255

Расчётные кейсы

Суммы в копейках, как того требует ТЗ. Столбец «эталон» посчитан вручную по тексту задания.

КейсэталонClaudeCodexCursor
A. WELCOME против категорийной скидки
телефон 5000 ₽ + 2 чехла по 300 ₽
скидка 50 643
итог 544 357
НДС 90 726
50 643
544 357
90 726
50 643
544 357
90 726
50 643
544 357
90 726
B. Ровно 10 000 ₽ и ровно 5 кг
противоречие в ТЗ
оба ответа
допустимы
доставка 0
итог 1 000 000
доставка 35 000
итог 1 035 000
доставка 35 000
итог 1 035 000
C. Вес 6000 г, заказ 1000 ₽
+20 ₽ за один полный кг сверх пяти
доставка 37 000
итог 137 000
НДС 22 833
37 000
137 000
22 833
37 000
137 000
22 833
37 000
137 000
22 833
D. Неизвестный промокод код 0,
факт виден
unknown unknown ignored_unknown
E. Пустая корзина нули,
без падения
итог 0 итог 0 итог 35 000 спорно
F. SUMMER26 при сумме ровно 5000 ₽
и при 4999 ₽
75 000 / 0 75 000 / 0 75 000 / 0 75 000 / 0
G. Скидка больше стоимости позиции
товар 100 ₽ + WELCOME 500 ₽
товары 0,
не в минус
0 ок 0 ок 0 ок
H. SUMMER26 под датой 2027
через faketime
просрочен,
не ошибка
expired expired ignored_expired
Что здесь важно

Кейс A — самое сложное место ТЗ: фиксированные 500 ₽ выданы «на корзину», а сравнивать выгоду нужно «по каждой позиции». Все трое независимо пришли к пропорциональному разнесению суммы по позициям с точностью до копейки и получили ровно один и тот же результат — 50 643. Расхождение в кейсе B — не ошибка ни у кого: ТЗ на этой границе противоречит само себе.

06Ловушки в ТЗ

Задание написано сплошной прозой, без нумерации: требования нужно было извлечь. Десять мест были заложены намеренно — ни одно из них агентам не подсвечивалось.

ЛовушкаClaudeCodexCursor
1. «Бесплатная от 10 000» против «платят включая ровно 10 000» — прямое противоречие вынес в NOTES и параметризовал обе трактовки снял молча отдельный пункт в «Неоднозначностях»
2. НДС включён в цену → ×20/120, а не ×0,2 верноверноверно
3. Граммы против килограммов: при 5000 г доплаты нет верноверно, тест 5000/5999/6000верно, отдельный тест границы
4. «Тесты проходят и в 2027» → нужен инъектируемый Clock Clock + FixedClock время в конструкторе ClockInterface + FixedClock
5. Дубли артикулов складываются (спрятано в описании структуры данных) дадада
6. Фикс-промокод «на корзину» нужно разложить по позициям пропорционально, наибольшие остатки пропорционально пропорционально, наибольшие остатки
7. Только копейки, float запрещён чисточисточисто
8. Просроченный промокод — состояние, а не ошибка 5 статусов с причинами статус + сообщение статус с причиной
9. Хвост задачи: README + CHANGELOG + NOTES + ненулевой код возврата всё, развёрнуто всё есть, но NOTES формальный всё, по делу
10. «Если что-то не сделал — напиши прямым текстом» раздел «Чего не сделал», признал непроверенное «невыполненных пунктов нет» — неточно три допущения прямым текстом

Ловушка №1 крупным планом

Это единственное место, где разброс оказался максимальным — и оно же лучше всего отделяет «выполняет» от «думает».

07Оценка тремя судьями

Результаты обезличены: скопированы в каталоги subject-1/2/3 в перемешанном порядке, git-история удалена, пути и упоминания авторства вычищены. Проверено грепом — ни в коде, ни в документации, ни в финальных ответах не осталось следов, по которым можно опознать автора. Каждый судья получил одинаковую рубрику на 30 пунктов и работал в своей копии материалов.

СудьяClaude CodeCodexCursorПорядок
Ручная приёмка (оператор)30,027,029,5Claude → Cursor → Codex
Судья Claude Code (Opus 5)30,028,530,0Claude → Cursor → Codex
Судья Codex (GPT-5.5)30,029,530,0Claude → Cursor → Codex
Среднее30,0028,3329,83полное совпадение
Ручных доделок до мержа01–20–1

Оба судьи выставили баллы вслепую и независимо друг от друга, и оба пришли к тому же порядку, что и ручная приёмка. Судья Codex, не зная, что оценивает в том числе работу собственного CLI, поставил ей третье место.

Где судьи разошлись

ПунктРасхождениеКак есть на самом деле
E1 у Codex
«противоречие замечено»
Судья Claude и оператор — 0. Судья Codex — 1. В NOTES у Codex решение заявлено, но слова о противоречии нет, и раздела неоднозначностей нет. Оценка 0 обоснована; судья Codex здесь оказался мягче к работе, которую сам же и породил.
A9 у Codex и Cursor
«понятная ошибка в stderr»
Оператор — 0,5. Оба судьи — 1. Проверено лично: цена 9223372036854775807 × 1000 роняет оба CLI в PHP Fatal с кодом 255 и стектрейсом вместо сообщения. Claude на том же входе отвечает кодом 1 и понятным текстом. Формально код ненулевой у всех, но «понятной ошибки» у двоих нет.
D3/D4 у Codex Оператор — 0,5 / 0,5. Судья Claude — 1 / 0,5. Судья Codex — 1 / 0,5. Все трое согласны, что декомпозиции нет: 267-строчный CartCalculator делает всё. Разошлись в том, считать ли NOTES из 11 строк без раздела неоднозначностей выполненным пунктом.

08Разбор по агентам

Claude Code — 30,0 из 30

Opus 5 · 891 с · 2,24 млн токенов · $3,92 · 0 доделок до мержа
Сильные стороны
Слабые стороны

Cursor — 29,8 из 30

Composer 2.5 · 155 с · 410 тыс. токенов · 0–1 доделка до мержа
Сильные стороны
Слабые стороны

Codex — 28,3 из 30

GPT-5.5 · 212 с · 277 тыс. токенов · 1–2 доделки до мержа
Сильные стороны
Слабые стороны

09Выводы

Если выбирать под задачу

КогдаКого братьПочему
Спорное ТЗ, цена ошибки высока, нужен разбор неоднозначностейClaude Code Единственный, кто вынес противоречие в конфигурируемый параметр и честно назвал непроверенное. Ноль доделок.
Типовая задача с понятными требованиями, важна скоростьCursor (Composer 2.5) Тот же уровень проработки в 5,7 раза быстрее и на собственной модели. Одна известная доделка.
Жёсткий лимит по токенам, требования однозначныCodex Функционально точен при 277 тыс. токенов, но хвост задачи придётся дописывать самому.
Что бы я поменял в методике

Ловушка с переполнением int в рубрике не была заложена, но именно она развела агентов сильнее, чем половина запланированных пунктов. В следующий прогон её стоит добавить явно — вместе с проверкой на пустую корзину, где расхождение оказалось содержательным, а не косметическим.